WorkManager giúp bạn dễ dàng thiết lập và lên lịch các yêu cầu tác vụ phức tạp. Bạn có thể sử dụng API cho các tình huống như sau:
- Các trình tự theo chuỗi của tác vụ chạy theo thứ tự được chỉ định
- Các trình tự được đặt tên riêng biệt, với các quy tắc cho những điều sẽ xảy ra nếu ứng dụng khởi chạy hai trình tự cùng tên
- Tác vụ truyền và trả về giá trị, kể cả các tác vụ theo chuỗi mà mỗi tác vụ sẽ truyền các đối số đến tác vụ tiếp theo trong chuỗi
Tác vụ theo chuỗi
Ứng dụng của bạn có thể cần chạy nhiều tác vụ theo thứ tự cụ thể.
WorkManager
cho phép bạn tạo và đưa trình tự công việc vào hàng đợi để chỉ định nhiều tác vụ và xác định thứ tự thực hiện các tác vụ.
Ví dụ: Giả sử ứng dụng của bạn có 3 đối tượng OneTimeWorkRequest
: workA
, workB
và workC
. Các tác vụ phải chạy theo thứ tự đó. Để thêm các đối tượng này vào hàng đợi, hãy tạo một trình tự bằng phương thức WorkManager.beginWith(OneTimeWorkRequest)
, truyền đối tượng OneTimeWorkRequest
đầu tiên. Phương thức đó trả về một đối tượng WorkContinuation
, giúp xác định một trình tự của các tác vụ. Sau đó, hãy thêm
các đối tượng OneTimeWorkRequest
còn lại theo thứ tự bằng phương thức WorkContinuation.then(OneTimeWorkRequest)
. Cuối cùng, hãy đưa toàn bộ trình tự vào hàng đợi bằng phương thức WorkContinuation.enqueue()
:
Kotlin
WorkManager.getInstance(myContext) .beginWith(workA) // Note: WorkManager.beginWith() returns a // WorkContinuation object; the following calls are // to WorkContinuation methods .then(workB) // FYI, then() returns a new WorkContinuation instance .then(workC) .enqueue()
Java
WorkManager.getInstance(myContext) .beginWith(workA) // Note: WorkManager.beginWith() returns a // WorkContinuation object; the following calls are // to WorkContinuation methods .then(workB) // FYI, then() returns a new WorkContinuation instance .then(workC) .enqueue();
WorkManager
chạy các tác vụ theo thứ tự mà bạn yêu cầu, theo các điều kiện ràng buộc đã chỉ định cho tác vụ. Nếu bất kỳ tác vụ nào trả về kết quả Result.failure()
thì toàn bộ trình tự sẽ kết thúc.
Bạn cũng có thể truyền nhiều đối tượng OneTimeWorkRequest
đến bất kỳ lệnh gọi nào trong số 2 lệnh beginWith(List<OneTimeWorkRequest>)
và then(List<OneTimeWorkRequest>)
. Nếu bạn truyền nhiều đối tượng OneTimeWorkRequest
đến một lệnh gọi phương thức duy nhất, thì WorkManager
sẽ chạy tất cả tác vụ đó (song) trước khi chạy phần còn lại của trình tự. Ví dụ:
Kotlin
WorkManager.getInstance(myContext) // First, run all the A tasks (in parallel): .beginWith(Arrays.asList(workA1, workA2, workA3)) // ...when all A tasks are finished, run the single B task: .then(workB) // ...then run the C tasks (in parallel): .then(Arrays.asList(workC1, workC2)) .enqueue()
Java
WorkManager.getInstance(myContext) // First, run all the A tasks (in parallel): .beginWith(Arrays.asList(workA1, workA2, workA3)) // ...when all A tasks are finished, run the single B task: .then(workB) // ...then run the C tasks (in parallel): .then(Arrays.asList(workC1, workC2)) .enqueue();
Bạn có thể tạo nhiều trình tự phức tạp hơn bằng cách kết hợp nhiều chuỗi với phương thức WorkContinuation.combine(List<OneTimeWorkRequest>)
. Ví dụ: Giả sử bạn muốn chạy trình tự như sau:
Để thiết lập trình tự này, hãy tạo 2 chuỗi riêng biệt rồi kết hợp các chuỗi đó thành một chuỗi thứ ba:
Kotlin
val chain1 = WorkManager.getInstance(myContext) .beginWith(workA) .then(workB) val chain2 = WorkManager.getInstance(myContext) .beginWith(workC) .then(workD) val chain3 = WorkContinuation .combine(Arrays.asList(chain1, chain2)) .then(workE) chain3.enqueue()
Java
WorkContinuation chain1 = WorkManager.getInstance(myContext) .beginWith(workA) .then(workB); WorkContinuation chain2 = WorkManager.getInstance(myContext) .beginWith(workC) .then(workD); WorkContinuation chain3 = WorkContinuation .combine(Arrays.asList(chain1, chain2)) .then(workE); chain3.enqueue();
Trong trường hợp này, WorkManager
chạy workA
trước workB
. Trình này cũng chạy workC
trước workD
. Sau khi cả workB
và workD
đều đã hoàn tất, WorkManager
sẽ chạy workE
.
Có một số biến thể của phương thức WorkContinuation
cung cấp cách viết ngắn gọn cho các tình huống cụ thể. Để biết thông tin chi tiết, hãy xem mục tài liệu tham khảo WorkContinuation
.
Trình tự công việc duy nhất
Bạn có thể tạo một trình tự công việc duy nhất, bằng cách bắt đầu trình tự bằng một lệnh gọi đến beginUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest)
thay vì beginWith(OneTimeWorkRequest)
.
Mỗi trình tự công việc duy nhất đều có tên; WorkManager
chỉ cho phép một trình tự công việc có tên đó tại một thời điểm. Khi tạo một trình tự công việc duy nhất mới, bạn sẽ chỉ định những việc WorkManager
phải làm nếu đã có một trình tự chưa hoàn tất có cùng tên:
- Huỷ trình tự hiện có và THAY THẾ trình tự đó bằng trình tự mới
- GIỮ trình tự hiện có và bỏ qua yêu cầu mới của bạn
- THÊM trình tự mới vào trình tự hiện tại, chạy tác vụ đầu tiên của trình tự mới sau khi tác vụ cuối cùng của trình tự hiện tại kết thúc
Trình tự công việc duy nhất có thể hữu ích nếu bạn có một tác vụ không nên đưa vào hàng đợi nhiều lần. Ví dụ: Nếu ứng dụng của bạn cần đồng bộ hoá dữ liệu với mạng, thì bạn có thể thêm một trình tự có tên là "đồng bộ hoá" và chỉ định hệ thống bỏ qua tác vụ mới của bạn nếu đã có một trình tự có tên đó. Trình tự công việc duy nhất cũng có thể hữu ích nếu bạn cần thiết lập dần một chuỗi dài của các tác vụ. Ví dụ: Một ứng dụng chỉnh sửa ảnh có thể cho phép người dùng huỷ một chuỗi dài các thao tác. Mỗi thao tác huỷ này có thể mất một chút thời gian, nhưng hệ thống phải thực hiện chúng theo đúng thứ tự. Trong trường hợp này, ứng dụng có thể tạo một chuỗi "huỷ" và thêm từng thao tác huỷ vào chuỗi nếu cần.
Tham số đầu vào và giá trị trả về
Để linh hoạt hơn nữa, bạn có thể truyền đối số tới các tác vụ của mình và các tác vụ sẽ trả kết quả về. Giá trị đã truyền và giá trị trả về là cặp khoá-giá trị. Để chuyển một đối số đến một tác vụ, hãy gọi phương thức WorkRequest.Builder.setInputData(Data)
trước khi tạo đối tượng WorkRequest
. Phương thức đó sẽ lấy đối tượng Data
mà bạn tạo bằng Data.Builder
. Lớp Worker
có thể truy cập vào các đối số đó bằng cách gọi Worker.getInputData()
. Để xuất ra một giá trị trả về, tác vụ phải bao gồm giá trị đó trong Result
(ví dụ: trả về Result.success(Data)
.
Bạn có thể nhận đầu ra bằng cách quan sát WorkInfo
của tác vụ.
Ví dụ: Giả sử bạn có một lớp Worker
thực hiện một phép tính cần nhiều thời gian. Đoạn mã sau đây cho thấy lớp Worker
sẽ trông như thế nào:
Kotlin
// Define the parameter keys: const val KEY_X_ARG = "X" const val KEY_Y_ARG = "Y" const val KEY_Z_ARG = "Z" // ...and the result key: const val KEY_RESULT = "result" // Define the Worker class: class MathWorker(context : Context, params : WorkerParameters) : Worker(context, params) { override fun doWork(): Result { val x = inputData.getInt(KEY_X_ARG, 0) val y = inputData.getInt(KEY_Y_ARG, 0) val z = inputData.getInt(KEY_Z_ARG, 0) // ...do the math... val result = myLongCalculation(x, y, z); //...set the output, and we're done! val output: Data = workDataOf(KEY_RESULT to result) return Result.success(output) } }
Java
// Define the Worker class: public class MathWorker extends Worker { // Define the parameter keys: public static final String KEY_X_ARG = "X"; public static final String KEY_Y_ARG = "Y"; public static final String KEY_Z_ARG = "Z"; // ...and the result key: public static final String KEY_RESULT = "result"; public MathWorker( @NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @Override public Result doWork() { // Fetch the arguments (and specify default values): int x = getInputData().getInt(KEY_X_ARG, 0); int y = getInputData().getInt(KEY_Y_ARG, 0); int z = getInputData().getInt(KEY_Z_ARG, 0); // ...do the math... int result = myLongCalculation(x, y, z); //...set the output, and we're done! Data output = new Data.Builder() .putInt(KEY_RESULT, result) .build(); return Result.success(output); } }
Để tạo công việc và truyền đối số, bạn nên sử dụng mã như sau:
Kotlin
val myData: Data = workDataOf("KEY_X_ARG" to 42, "KEY_Y_ARG" to 421, "KEY_Z_ARG" to 8675309) // ...then create and enqueue a OneTimeWorkRequest that uses those arguments val mathWork = OneTimeWorkRequestBuilder<MathWorker>() .setInputData(myData) .build() WorkManager.getInstance(myContext).enqueue(mathWork)
Java
// Create the Data object: Data myData = new Data.Builder() // We need to pass three integers: X, Y, and Z .putInt(KEY_X_ARG, 42) .putInt(KEY_Y_ARG, 421) .putInt(KEY_Z_ARG, 8675309) // ... and build the actual Data object: .build(); // ...then create and enqueue a OneTimeWorkRequest that uses those arguments OneTimeWorkRequest mathWork = new OneTimeWorkRequest.Builder(MathWorker.class) .setInputData(myData) .build(); WorkManager.getInstance(myContext).enqueue(mathWork);
Giá trị trả về sẽ có trong WorkInfo
của tác vụ:
Kotlin
WorkManager.getInstance(myContext).getWorkInfoByIdLiveData(mathWork.id) .observe(this, Observer { info -> if (info != null && info.state.isFinished) { val myResult = info.outputData.getInt(KEY_RESULT, myDefaultValue) // ... do something with the result ... } })
Java
WorkManager.getInstance(myContext).getWorkInfoByIdLiveData(mathWork.getId()) .observe(lifecycleOwner, info -> { if (info != null && info.getState().isFinished()) { int myResult = info.getOutputData().getInt(KEY_RESULT, myDefaultValue)); // ... do something with the result ... } });
Nếu bạn liên kết các tác vụ, thì đầu ra của một tác vụ sẽ có sẵn dưới dạng đầu vào của tác vụ tiếp theo trong chuỗi đó. Nếu đó là một chuỗi đơn giản, với một
OneTimeWorkRequest
sau đó là một OneTimeWorkRequest
duy nhất khác, thì tác vụ đầu tiên trả về kết quả bằng cách
gọi Result.success(Data)
và tác vụ tiếp theo sẽ tìm nạp kết quả đó bằng cách gọi getInputData()
. Nếu chuỗi phức tạp hơn, ví dụ: Vì nhiều tác vụ đều gửi đầu ra đến duy nhất một tác vụ tiếp theo – bạn có thể khai báo InputMerger
trên OneTimeWorkRequest.Builder
để chỉ định điều sẽ xảy ra nếu các tác vụ khác nhau trả về đầu ra bằng cùng một khoá.
Tài nguyên khác
Để tìm hiểu thêm về WorkManager, hãy tham khảo các tài nguyên khác sau đây.
Mẫu
- Ứng dụng mẫu WorkManager
- Sunflower, một ứng dụng làm vườn minh hoạ các phương pháp hay nhất để phát triển trên Android bằng Android Jetpack.