(九、3)高級WorkManager主題

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()方法連接多個鏈來創建更復雜的序列。 例如,假設您要運行如下序列:


圖1.您可以使用WorkContinuation來設置復雜的鏈式任務。

要設置此序列,請創建兩個單獨的鏈,然后將它們連接到第三個鏈中:

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,以指定當不同任務返回具有相同鍵的輸出時應該發生什么。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,881評論 18 139
  • WorkManager架構組件是用來管理后臺工作任務。這個時候你可能會奇怪了Android不是已經 有很多管...
    tuacy閱讀 6,508評論 4 14
  • 1、概述 在 I / O '18中,Google發布了Android Jetpack。它是一組庫,工具和架構指南,...
    高丕基閱讀 7,540評論 1 12
  • 晚上,接閨女回來,督促孩子快寫作業,我就去做飯。問問閨女想吃啥,閨女說想吃意面。“中午剛吃過,晚上換換樣...
    梓墨麻麻閱讀 154評論 0 0
  • 文明與野蠻 是人類自己給自己 劃出的界限 人類的歷史 說長也不長 說短也不短 但有一點是肯定的 文明的年齡 遠遠小...
    蘇懷亮文字閱讀 205評論 0 0