管理工作

定義您的 Worker你的 WorkRequest 最後一步是將工作加入佇列將工作排入佇列的最簡單方式 那就是呼叫 WorkManager enqueue() 方法,並傳遞 WorkRequest 決定要執行的版本

Kotlin

val myWork: WorkRequest = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork)

Java

WorkRequest myWork = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork);

因此,建議您在將工作排入佇列時謹慎小心,以免重複。 舉例來說,應用程式可能會嘗試 每 24 小時將記錄檔記錄傳送至後端服務有事時您就會 最終會將相同的工作多次排入佇列 執行一次 如要達到這個目標,您可以將工作安排為「不重複工作」

不重複工作

「不重複工作」這個強大概念 可確保您只有一個物件 指定一次特定名稱的工作執行個體。唯一名稱與 ID 不同 為人類可讀且由開發人員指定,而不是自動產生 由 WorkManager 處理取消喜歡 tags,不重複 只會與單一工作例項建立關聯。

不重複工作可套用至一次性和週期性工作。您可以建立 不同的工作序列來呼叫不同的方法,實際情況取決於 安排週期性或一次性工作

這兩種方法都接受 3 個引數:

  • uniqueWorkName - 用來識別作品的 String 請求。
  • existingWorkPolicy - 向 WorkManager 指示要執行的動作的 enum 如果有同一名稱已有未完成的工作鏈結詳情請見 衝突解決政策
  • work - 要安排的 WorkRequest

只要使用不重複的工作,我們就能修正先前所述的重複排程問題。

Kotlin

val sendLogsWorkRequest =
       PeriodicWorkRequestBuilderS<endLogsWorker(>24, TimeUnit.HOURS)
           .setConstraints(Constraints.Builder()
               .setRequiresCharging(true)
               .build()
            )
           .build()
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
           "sendLogs",
           ExistingPeriodicWorkPolicy.KEEP,
           sendLogsWorkRequest
)

Java

PeriodicWorkRequest sendLogsWorkRequest = new
      PeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS)
              .setConstraints(new Constraints.Builder()
              .setRequiresCharging(true)
          .build()
      )
     .build();
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
     "sendLogs",
     ExistingPeriodicWorkPolicy.KEEP,
     sendLogsWorkRequest);

現在,如果 sendLogs 工作已在佇列中,而程式碼同時執行, 工作,而且不會新增任何工作。

如果您需要逐步建構 長時間執行任務例如,相片編輯應用程式可能會讓使用者復原 需要長時間的動作每項復原作業可能需要一些時間才能完成,但 這些動作必須以正確順序執行在這個範例中,應用程式 建立「復原」鏈結並視需要將每項復原作業附加至鏈結。 請參閱將工作鏈結在一起一文 ,掌握更多詳細資訊。

衝突解決政策

安排不重複工作時,您必須告知 WorkManager 在何時採取行動 發生衝突。如要這麼做,請在將工作加入佇列時傳遞列舉值。

如果是一次性工作,您需要提供 ExistingWorkPolicy, 支援 4 個處理衝突的選項。

  • REPLACE 部 重新投入工作這個選項會取消現有工作。
  • KEEP 個既有工作和 即可忽略新工作
  • APPEND 要將新工作設為 停用現有工作這項政策會使新作業生效 鏈結至 現有工作,在現有工作結束後執行。

現有工作會成為新工作的「先決條件」。如果現有作業 變成 CANCELLEDFAILED,而新工作也會變為 CANCELLEDFAILED。 如果您希望新工作不受現有工作狀態影響 請改用 APPEND_OR_REPLACE

  • APPEND_OR_REPLACE敬上 函式與 APPEND 類似,差別在於前者不受 事前準備工作狀態。如果現有作品為 CANCELLEDFAILED,新工作仍會執行。

如果是週期性工作,您必須提供 ExistingPeriodicWorkPolicy、 支援 2 個選項:REPLACEKEEP。這些選項的作用 做為 ExistingWorkPolicy 的對應項目

觀察你的工作

將工作加入佇列後,您可以隨時透過查詢 WorkManager 依據其 nameid 或相關 tag

Kotlin

// by id
workManager.getWorkInfoById(syncWorker.id) // ListenableFutureW<orkInfo<>/span>

// by name
workManager.getWorkInfosForUniqueWork("sync") // ListenableFutureL<istW<orkInfo<>/span>
>
// by tag
workManager.getWorkInfosByTag("syncTag") // ListenableFutureL<istW<orkInfo<>/span>
>

Java

// by id
workManager.getWorkInfoById(syncWorker.id); // ListenableFutureW<orkInfo<>/span>

// by name
workManager.getWorkInfosForUniqueWork("sync"); // ListenableFutureL<istW<orkInfo<>/span>
>
// by tag
workManager.getWorkInfosByTag("syncTag"); // ListenableFutureL<istW<orkInfo<>/span>
>

查詢會傳回 ListenableFuture敬上 WorkInfo 物件的所有值,其中含有 id 工作、其標記、其 目前 State,以及任何輸出資料 設定方式 Result.success(outputData)

各個 Service 適用的 LiveData 變化版本 方法可讓您註冊 WorkInfo 事件監聽器。比方說,在活動期間 部分工作已成功完成,您可以依下列方式進行設定:

Kotlin

workManager.getWorkInfoByIdLiveData(syncWorker.id)
               .observe(viewLifecycleOwner) { workInfo -
>   if(workInfo?.state == WorkInfo.State.SUCCEEDED) {
       Snackbar.make(requireView(), 
      R.string.work_completed, Snackbar.LENGTH_SHORT)
           .show()
   }
}

Java

workManager.getWorkInfoByIdLiveData(syncWorker.id)
        .observe(getViewLifecycleOwner(), workInfo - >{
    if (workInfo.getState() != null 
&&            workInfo.getState() == WorkInfo.State.SUCCEEDED) {
        Snackbar.make(requireView(),
                    R.string.work_completed, Snackbar.LENGTH_SHORT)
                .show();
   }
});

複雜的工作查詢

WorkManager 2.4.0 以上版本支援使用 WorkQuery 物件。WorkQuery 支援 使用標記、狀態和不重複工作名稱的組合來查詢工作。

以下範例顯示如何找出所有與代碼「syncTag」一起執行的作業。 處於 FAILEDCANCELLED 狀態,且專屬的工作名稱 「preProcess」或「sync」。

Kotlin

val workQuery = WorkQuery.Builder
       .fromTags(listOf("syncTag"))
       .addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
       .addUniqueWorkNames(listOf("preProcess", "sync")
    )
   .build()

val workInfos: ListenableFutureL<istW<orkInfo >>= workManager.getWorkInfos(workQuery)

Java

WorkQuery workQuery = WorkQuery.Builder
       .fromTags(Arrays.asList("syncTag"))
       .addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
       .addUniqueWorkNames(Arrays.asList("preProcess", "sync")
     )
    .build();

ListenableFutureL<istW<orkInfo >>workInfos = workManager.getWorkInfos(workQuery);

WorkQuery 中的每個元件 (標記、狀態或名稱) 都具有 AND 關係。而元件中的每個值都具有 OR 邏輯關係。例如:(name1 OR name2 OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)

WorkQuery 也適用於 LiveData 對等項目 getWorkInfosLiveData()

取消及停止工作

如果不再需要執行已排入佇列的工作, 取消。工作可以透過 nameidtag 取消 相關聯的資源

Kotlin

// by id
workManager.cancelWorkById(syncWorker.id)

// by name
workManager.cancelUniqueWork("sync")

// by tag
workManager.cancelAllWorkByTag("syncTag")

Java

// by id
workManager.cancelWorkById(syncWorker.id);

// by name
workManager.cancelUniqueWork("sync");

// by tag
workManager.cancelAllWorkByTag("syncTag");

實際上,WorkManager 會檢查 作品的 State。如果工作內容是 已完成 基本上不會有任何影響否則,工作狀態會變更為 CANCELLED 和工作 因此無法再執行不限 WorkRequest職缺取決於 這個領域 且為 CANCELLED

目前使用 RUNNING 網域 接到來電 ListenableWorker.onStopped()。 覆寫這個方法即可處理任何潛在的清理作業。查看停止 執行中的 worker

停止執行中的工作站

以下幾個不同的原因可能會導致 WorkManager 停止執行 Worker

  • 您已明確要求取消 (透過致電) 例如 WorkManager.cancelWorkById(UUID))。
  • 就「不重複工作」來說 您明確將新的 WorkRequest 加入佇列,其中包含 ExistingWorkPolicy/ REPLACE。 系統會立即將舊的 WorkRequest 視為取消,
  • 也不會再滿足您的工作限制條件。
  • 系統因故指示應用程式停止工作。這可以 就會發生這種情形。工作: 排定於稍後重試

在下列情況下,工作站將會停止運作。

您應配合取消所有進行中的工作,並釋出任何 資源數量舉例來說, 處理資料庫和檔案的方式有兩種機制 處理工作工作站何時停止運作

onStopped() 回呼

WorkManager 叫用 ListenableWorker.onStopped()敬上 工作站停止執行。覆寫這個方法即可關閉 您可操作的任何資源

isStopped() 屬性

您可以呼叫 ListenableWorker.isStopped() 方法,檢查工作站是否已停止。如果您是 在工作站中執行長時間或重複作業時 請經常檢查這項資源,並視為盡快停止工作的信號 。

注意:WorkManager 會忽略 工作站設定的 Result 接收到 onStop 信號,因為已將 worker 視為 已停止。