すでにキューに登録されている処理を更新する

WorkManager では、WorkRequest をキューに追加した後で更新できます。これは、制約を頻繁に変更する場合や、ワーカーをその場で更新する必要がある大規模なアプリで必要になることがよくあります。WorkManager バージョン 2.8.0 以降では、updateWork() API がこれを行う手段になっています。

updateWork() メソッドを使用すると、新しい要素を手動でキャンセルしてキューに登録するプロセスを必要とせずに、WorkRequest の特定の要素をその場で変更できます。これにより、開発プロセスが大幅に簡素化されます。

処理のキャンセルを避ける

通常は、既存の WorkRequest のキャンセルや新しい WorkRequest のキュー登録は避けてください。このように設定すると、アプリが特定のタスクを繰り返して、大量の追加コードを記述する必要が生じる場合があります。

WorkRequest のキャンセルがうまくいかない場合の例を以下に示します。

  • バックエンド リクエスト: サーバーに送信するペイロードの計算中に Worker をキャンセルすると、新しい Worker を最初からやり直し、高価な可能性があるペイロードを再計算する必要があります。
  • スケジュール: PeriodicWorkRequest をキャンセルし、新しい PeriodicWorkRequest を同じスケジュールで実行する場合は、新しい実行時間が前の処理リクエストと一致するように時間オフセットを計算する必要があります。

updateWork() API を使用すると、新しいリクエストをキャンセルしてキューに入れることなく、処理リクエストの制約やその他のパラメータを更新できます。

処理をキャンセルするタイミング

updateWork() を呼び出すのではなく、WorkRequest を直接キャンセルする必要がある場合があります。これは、キューに投入した処理の基本的な性質を変更したい場合に行います。

提出物を更新するタイミング

ユーザーの写真を毎日バックアップする写真アプリを例に考えます。そのために PeriodicWorkRequest がキューに追加されています。WorkRequest には、デバイスを充電して Wi-Fi に接続する必要があるという制約があります。

しかし、ユーザーが急速充電器を使ってデバイスを充電するのは 1 日に 20 分間だけです。この場合、アプリは WorkRequest を更新して充電の制約を緩和し、デバイスが完全に充電されていない場合でも写真をアップロードできるようにすることをおすすめします。

この場合、updateWork() メソッドを使用して処理リクエストの制約を更新できます。

提出物を更新する方法

updateWork() メソッドを使用すると、既存の WorkRequest を簡単に更新できます。新しい WorkRequest をキャンセルしてキューに登録する必要はありません。

キューに追加された処理を更新する手順は次のとおりです。

  1. キューに追加された処理の既存の ID を取得する: 更新する WorkRequest の ID を取得します。この ID は、いずれかの getWorkInfo API を使用して取得できます。また、最初の WorkRequest から ID を手動で保持して、後でパブリック プロパティ WorkRequest.id を使用して取得できるようにキューに登録することもできます。
  2. 新しい WorkRequest を作成する: 新しい WorkRequest を作成し、WorkRequest.Builder.setID() を使用して既存の WorkRequest の ID と一致する ID を設定します。
  3. 制約を設定する: WorkRequest.Builder.setConstraints() を使用して WorkManager の新しい制約を渡します。
  4. updateWork を呼び出す: 新しい WorkRequest を updateWork() に渡します。

更新(仕事用)の例

以下に、写真のアップロードに使用する WorkRequest のバッテリー制約を、updateWork() メソッドを使用して変更するコード スニペットを Kotlin で示します。

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 を更新するたびに、generation が 1 ずつ増えます。これにより、現在キューに追加されている WorkRequest を正確に追跡できます。世代を使用すると、処理リクエストのモニタリング、トレース、テストをより細かく制御できます。

WorkRequest の生成を取得する手順は次のとおりです。

  1. WorkInfo: WorkManager.getWorkInfoById() を呼び出して、WorkRequest に対応する WorkInfo のインスタンスを取得します。
    • WorkInfo を返すいくつかのメソッドの 1 つを呼び出すことができます。詳細については、WorkManager リファレンスをご覧ください。
  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.REPLACE を使用して PeriodicWorkRequest をキューに追加することでした。同じ一意の id を持つ保留中の PeriodicWorkRequest がある場合、新しい処理リクエストはキャンセルされて削除されます。このポリシーは非推奨となり、ExistingPeriodicWorkPolicy.UPDATE を使用したワークフローに置き換えられました。

たとえば、PeriodicWorkRequestenqueueUniquePeriodicWork を使用する場合、ExistingPeriodicWorkPolicy.UPDATE ポリシーで新しい PeriodicWorkRequest を初期化できます。同じ一意名を持つ保留中の PeriodicWorkRequest がある場合、WorkManager はそれを新しい仕様に更新します。このワークフローに従うと、updateWork() を使用する必要はありません。