WorkManager
可以輕松設置和安排精心設計的任務請求。 您可以將API用于以下場景:
- 以指定順序運行的鏈式任務序列
- 唯一的命名序列,包含應用程序啟動兩個具有相同名稱的序列時會發生什么的規則
- 傳遞和返回值的任務,包括每個任務將參數傳遞給鏈中下一個任務的鏈式任務
一、鏈式任務
您的應用可能需要按特定順序運行多個任務。WorkManager
允許您創建和排隊指定多個任務的工作序列,以及它們應運行的順序。
例如,假設您的應用有三個OneTimeWorkRequest對象:workA,workB和workC。 任務必須按該順序運行。 要將它們排入隊列,請使用WorkManager.beginWith()方法創建一個序列,并傳遞第一個OneTimeWorkRequest對象; 該方法返回一個WorkContinuation對象,該對象定義了一系列任務。 然后依次使用WorkContinuation.then()添加剩余的OneTimeWorkRequest對象,最后使用WorkContinuation.enqueue()將整個序列排入隊列:
WorkManager.getInstance()
.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根據每個任務指定的約束以請求的順序運行任務。 如果任何任務返回Worker.Result.FAILURE,則整個序列結束。
您還可以將多個OneTimeWorkRequest對象傳遞給任何beginWith()和.then()調用。 如果將多個OneTimeWorkRequest對象傳遞給單個方法調用,則WorkManager會在運行其余序列之前運行所有這些任務(并行)。 例如:
WorkManager.getInstance()
// First, run all the A tasks (in parallel):
.beginWith(workA1, workA2, workA3)
// ...when all A tasks are finished, run the single B task:
.then(workB)
// ...then run the C tasks (in any order):
.then(workC1, workC2)
.enqueue();
您可以通過使用WorkContinuation.combine()方法連接多個鏈來創建更復雜的序列。 例如,假設您要運行如下序列:
要設置此序列,請創建兩個單獨的鏈,然后將它們連接到第三個鏈中:
WorkContinuation chain1 = WorkManager.getInstance()
.beginWith(workA)
.then(workB);
WorkContinuation chain2 = WorkManager.getInstance()
.beginWith(workC)
.then(workD);
WorkContinuation chain3 = WorkContinuation
.combine(chain1, chain2)
.then(workE);
chain3.enqueue();
在這種情況下,WorkManager在工作之前運行workA。 它還在工作之前運行。 在work和workD完成后,WorkManager運行workE。
注意:當WorkManager按順序運行每個子鏈時,無法保證chain1中的任務可能與chain2中的任務重疊。 例如,workB可能在workC之前或之后運行,或者它們可能同時運行。 唯一的承諾是每個子鏈中的任務將按順序運行; 也就是說,workB在workA完成之后才會啟動。
WorkContinuation方法有許多變體可以為特定情況提供縮寫。 例如,有一個WorkContinuation.combine(OneTimeWorkRequest,WorkContinuation ...)方法,它指示WorkManager完成所有指定的WorkContinuation鏈,然后使用指定的OneTimeWorkRequest完成。 有關詳細信息,請參閱WorkContinuation參考。
二、獨特的工作順序
您可以通過調用beginUniqueWork()而不是beginWith()來創建一個唯一的工作序列。 每個獨特的工作序列都有一個名稱; WorkManager一次只允許一個具有該名稱的工作序列。 創建新的唯一工作序列時,如果已經有一個具有相同名稱的未完成序列,則指定WorkManager應執行的操作:
- 取消現有序列并將其替換為新序列
- 保留現有序列并忽略您的新請求
- 將新序列附加到現有序列,在現有序列的最后一個任務完成后運行新序列的第一個任務
如果您的任務不應多次排隊,則唯一的工作順序非常有用。 例如,如果您的應用需要將其數據同步到網絡,您可以將名為“sync”的序列排隊,并指定如果已經有一個具有該名稱的序列,則應忽略您的新任務。 如果您需要逐步建立一長串任務,那么獨特的工作順序也很有用。 例如,照片編輯應用程序可能允許用戶撤消一長串操作。 每個撤消操作可能需要一段時間,但必須以正確的順序執行。 在這種情況下,應用程序可以創建“撤消”鏈并根據需要將每個撤消操作附加到鏈。
三、輸入參數和返回值
為了獲得更大的靈活性,您可以將參數傳遞給任務并讓任務返回結果。 傳遞和返回的值是鍵值對。 要將參數傳遞給任務,請在創建WorkRequest對象之前調用WorkRequest.Builder.setInputData()方法。 該方法采用Data對象,您使用Data.Builder創建。 Worker類可以通過調用Worker.getInputData()來訪問這些參數。 要輸出返回值,任務調用Worker.setOutputData(),它接受一個Data對象; 您可以通過觀察任務的LiveData <WorkStatus>來獲取輸出。
例如,假設您有一個執行耗時計算的Worker類。 以下代碼顯示了Worker類的外觀:
// 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 Worker.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 = myCrazyMathFunction(x, y, z);
//...set the output, and we're done!
Data output = new Data.Builder()
.putInt(KEY_RESULT, result)
.build();
setOutputData(output);
return Result.SUCCESS;
}
}
要創建工作并傳遞參數,您可以使用如下代碼:
// 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().enqueue(mathWork);
返回的值將在任務的WorkStatus中可用:
WorkManager.getInstance().getStatusById(mathWork.getId())
.observe(lifecycleOwner, status -> {
if (status != null && status.getState().isFinished()) {
int myResult = status.getOutputData().getInt(KEY_RESULT,
myDefaultValue));
// ... do something with the result ...
}
});
如果鏈接任務,則一個任務的輸出可用作鏈中下一個任務的輸入。 如果它是一個簡單的鏈,只有一個OneTimeWorkRequest后跟另一個OneTimeWorkRequest,第一個任務通過調用setOutputData()返回其結果,下一個任務通過調用getInputData()獲取該結果。 如果鏈更復雜 - 例如,因為幾個任務都將輸出發送到單個后續任務 - 您可以在OneTimeWorkRequest.Builder上定義一個InputMerger,以指定當不同任務返回具有相同鍵的輸出時應該發生什么。