更新已排入佇列的工作

WorkRequest 排入佇列後,WorkManager 可讓您更新該物件。對於經常變更限製或需要即時更新工作站的大型應用程式而言,通常這是不可或缺的步驟。自 WorkManager 2.8.0 版起,updateWork() API 是這樣做的方法。

updateWork() 方法可讓您即時變更 WorkRequest 的某些部分,不必執行手動取消並排入新的程序。這可大幅簡化開發程序

避免取消工作

一般而言,您應避免取消現有的 WorkRequest 並將新的 WorkRequest 排入佇列。這樣做可能會導致應用程式重複執行特定工作,而您可能需要編寫大量的額外程式碼。

請參考以下範例,瞭解取消 WorkRequest 可能會造成困難的地方:

  • 後端要求:如果您在計算要傳送至伺服器的酬載時取消 Worker,新的 Worker 就必須重新開始,並重新運算可能昂貴的酬載。
  • 排程:如果您取消 PeriodicWorkRequest,並希望新的 PeriodicWorkRequest 在相同排程中執行,就必須計算時間偏移,確保新的執行時間與先前的工作要求一致。

updateWork() API 可讓您更新工作要求的限制條件和其他參數,而不會取消並排入新的要求。

取消工作的時機

在某些情況下,您應該直接取消 WorkRequest,而不是呼叫 updateWork()。當您要變更已排入佇列的工作的基本性質時,請執行以上操作。

更新工作時間

假設有一個相片應用程式每天備份使用者的相片。該應用程式已將 PeriodicWorkRequest 加入佇列,以便執行此作業。WorkRequest 設有限制,需要裝置充電並連上 Wi-Fi。

不過,使用者只要使用快速充電器,每天僅為裝置充電 20 分鐘。在這種情況下,應用程式可能需要更新 WorkRequest 來放寬充電限制,即使裝置未充飽電,仍可上傳相片。

在這種情況下,您可以使用 updateWork() 方法更新工作要求的限制條件。

如何更新工作

updateWork() 方法提供更新現有 WorkRequest 的簡易方法,不必取消新的帳戶並將其排入佇列。

如要使用更新已排入佇列的工作,請按照下列步驟操作:

  1. 取得已排入佇列的工作的現有 ID:取得要更新的 WorkRequest 的 ID。您可以使用任何 getWorkInfo API 擷取這個 ID,也可以手動保留初始 WorkRequest 中的 ID,以便日後透過公開屬性 WorkRequest.id 擷取,然後再排入佇列。
  2. 建立新的 WorkRequest:建立新的 WorkRequest,並使用 WorkRequest.Builder.setID() 將其 ID 設定為與現有 WorkRequest 相符。
  3. 設定限制:使用 WorkRequest.Builder.setConstraints() 傳遞 WorkManager 新的限制。
  4. 呼叫 updateWork:將新的 WorkRequest 傳遞至 updateWork()

更新工作範例

以下是 Kotlin 的程式碼片段範例,示範如何使用 updateWork() 方法變更用於上傳相片的 WorkRequest 電池限制:

suspend fun updatePhotoUploadWork() {
    // Get instance of WorkManager.
    val workManager = WorkManager.getInstance(context)

    // Retrieve the work request ID. In this example, the work being updated is unique
    // work so we can retrieve the ID using the unique work name.
    val photoUploadWorkInfoList = workManager.getWorkInfosForUniqueWork(
        PHOTO_UPLOAD_WORK_NAME
    ).await()

    val existingWorkRequestId = photoUploadWorkInfoList.firstOrNull()?.id ?: return

    // Update the constraints of the WorkRequest to not require a charging device.
    val newConstraints = Constraints.Builder()
        // Add other constraints as required here.
        .setRequiresCharging(false)
        .build()

    // Create new WorkRequest from existing Worker, new constraints, and the id of the old WorkRequest.
    val updatedWorkRequest: WorkRequest =
        OneTimeWorkRequestBuilder<MyWorker>()
            .setConstraints(newConstraints)
            .setId(existingWorkRequestId)
            .build()

    // Pass the new WorkRequest to updateWork().
    workManager.updateWork(updatedWorkRequest)
}

處理結果

updateWork() 會傳回 ListenableFuture<UpdateResult>。指定的 UpdateResult 可能包含其中一個值,概略說明 WorkManager 是否能套用變更。同時也指出可套用變更的時間。

詳情請參閱 updateWork() UpdateResult 參考資料

與世代共事的追蹤工作

每次更新 WorkRequest 時,其產生就會加 1。這可讓您確切追蹤目前排入佇列的 WorkRequest。產生版本可讓您進一步掌控在觀察、追蹤和測試工作要求時。

如要取得 WorkRequest 的產生,請按照下列步驟操作:

  1. WorkInfo:呼叫 WorkManager.getWorkInfoById() 以擷取對應於 WorkRequestWorkInfo 執行個體。
  2. getGeneration:在 WorkInfo 的執行個體上呼叫 getGeneration()。傳回的 Int 會與 WorkRequest 的產生對應。
    • 請注意,沒有產生欄位或屬性,只有 WorkInfo.getGeneration() 方法。

測試群組產生範例

以下是上述工作流程實作範例,以擷取 WorkRequest 產生的內容。

// Get instance of WorkManager.
val workManager = WorkManager.getInstance(context)

// Retrieve WorkInfo instance.
val workInfo = workManager.getWorkInfoById(oldWorkRequestId)

// Call getGeneration to retrieve the generation.
val generation = workInfo.getGeneration()

更新工作政策

以往,更新定期工作的建議解決方案是將使用政策 ExistingPeriodicWorkPolicy.REPLACEPeriodicWorkRequest 排入佇列。如果有多個待處理 PeriodicWorkRequest 具有相同的不重複 id,新的工作要求就會取消並刪除。這項政策現已淘汰,改用 ExistingPeriodicWorkPolicy.UPDATE 的工作流程。

舉例來說,將 enqueueUniquePeriodicWorkPeriodicWorkRequest 搭配使用時,您可以使用 ExistingPeriodicWorkPolicy.UPDATE 政策初始化新的 PeriodicWorkRequest。如果如果有待處理 PeriodicWorkRequest 且名稱不重複,WorkManager 會將其更新為新的規格。根據這個工作流程,您並不需要使用 updateWork()