作業の管理

WorkerWorkRequest を定義したら、最後に処理をキューに登録します。処理をキューに登録する最も簡単な方法は、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 時間ごとにバックエンド サービスにログをアップロードしようとする場合があります。注意しないと、1 回しか実行する必要のないタスクを何回もキューに登録してしまう可能性があります。これを回避するために、処理を一意処理としてスケジュール設定できます。

一意処理

一意処理とは、特定の名前が付けられた処理インスタンスが同時に 1 つだけ存在することを保証する強力な概念です。一意の名前は ID とは異なり、人間が読むことができ、WorkManager が自動生成するのではなくデベロッパーが指定します。また、タグとは異なり、1 つの処理インスタンスにのみ関連付けられます。

一意処理は、1 回限りの処理と定期的な処理の両方に適用できます。繰り返し処理と 1 回限りの処理のどちらのスケジュールを設定しているかに応じて、次のいずれかのメソッドを呼び出して、一意処理シーケンスを作成できます。

どちらのメソッドも次の 3 つの引数を受け入れます。

  • uniqueWorkName - WorkRequest を一意に識別するために使用される String
  • existingWorkPolicy - 一意の名前が付けられた未完了の処理チェーンがまだ存在する場合に、WorkManager が行う必要がある処理を指定する enum。詳細については、競合解決ポリシーをご覧ください。
  • work - スケジュール設定を行う WorkRequest

一意処理を使用することで、前述したスケジュール設定の重複の問題を解決できます。

Kotlin


val sendLogsWorkRequest =
       PeriodicWorkRequestBuilder<SendLogsWorker>(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 が行う処理を指定する必要があります。これを行うには、処理をキューに登録するときに列挙型を渡します。

1 回限りの処理では、ExistingWorkPolicy を指定します。これにより、競合を処理する 4 つのオプションがサポートされます。

  • REPLACE は、新しい処理で既存の処理を置き換えます。このオプションでは、既存の処理はキャンセルされます。
  • KEEP は、既存の処理を保持し、新しい処理を無視します。
  • APPEND は、新しい処理を既存の処理の最後に追加します。このポリシーでは、新しい処理が既存の処理に連結され、既存の処理の完了後に実行されます。

既存の処理が、新しい処理の前提条件になります。既存の処理が CANCELLED または FAILED になると、新しい処理も CANCELLED または FAILED になります。既存の処理のステータスに関係なく新しい処理を実行するには、代わりに APPEND_OR_REPLACE を使用します。

  • APPEND_OR_REPLACE は、前提条件の処理のステータスに依存しないという点以外は、APPEND と同じように機能します。既存の処理が CANCELLED または FAILED の場合でも、新しい処理は引き続き実行されます。

定期的な処理の場合は、REPLACEKEEP の 2 つのオプションをサポートする ExistingPeriodicWorkPolicy を指定します。これらのオプションは、ExistingWorkPolicy のオプションと同じように機能します。

処理の監視

処理をキューに登録した後、nameid、または処理に関連する tag で WorkManager にクエリすることによって、いつでもステータスを確認できます。

Kotlin


// by id
workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo>

// by name
workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>>

// by tag
workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>

Java


// by id
workManager.getWorkInfoById(syncWorker.id); // ListenableFuture<WorkInfo>

// by name
workManager.getWorkInfosForUniqueWork("sync"); // ListenableFuture<List<WorkInfo>>

// by tag
workManager.getWorkInfosByTag("syncTag"); // ListenableFuture<List<WorkInfo>>


このクエリは、WorkInfo オブジェクトの ListenableFuture を返します。これには処理の id、タグ、現在の State、および Result.success(outputData) 経由で設定されたすべての出力データが含まれます。

各メソッドの 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」というタグが付けられ、状態が FAILED または CANCELLED で、「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: ListenableFuture<List<WorkInfo>> = 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();

ListenableFuture<List<WorkInfo>> workInfos = workManager.getWorkInfos(workQuery);

WorkQuery の各コンポーネント(タグ、状態、名前)は、AND で他のコンポーネントと連結されます。コンポーネント内の各値は OR で連結されます(例: (name1 OR name2 OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...))。

WorkQuery は LiveData の同等機能である getWorkInfosLiveData() とも連携します。

処理のキャンセルと停止

キューに登録した処理を実行する必要がなくなった場合、処理をキャンセルするよう要求することができます。処理をキャンセルするには、nameid、または関連する tag を使用します。

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 によって停止される理由には、次のようなものがあります。

  • ワーカーをキャンセルするよう明示的に要求した(WorkManager.cancelWorkById(UUID) を呼び出したなど)。
  • 一意処理の場合に、ExistingWorkPolicyREPLACE に設定された新しい WorkRequest を明示的にキューに登録した。古い WorkRequest は直ちにキャンセル済みと判断されます。
  • 処理の制約が満たされなくなった。
  • システムがアプリに対し、なんらかの理由で処理を停止するよう指示した。これは、実行期限の 10 分を超えた場合に行われることがあります。処理が後で再試行されるようにスケジュール設定されます。

以上のような状況では、ワーカーは停止します。

進行中のすべての処理を協調的に中止し、ワーカーが保持しているリソースを解放する必要があります。たとえば、開いているハンドル、データベース、ファイルなどを閉じる必要があります。ワーカーが停止しているかどうかを確認するために、次のいずれかのメカニズムを利用できます。

onStopped() コールバック

WorkManager は、ワーカーが停止するとすぐに ListenableWorker.onStopped() を呼び出します。このメソッドをオーバーライドして、保持している可能性のあるリソースをすべて閉じます。

isStopped() プロパティ

ListenableWorker.isStopped() メソッドを呼び出して、ワーカーがすでに停止しているかどうかを確認できます。ワーカーで長時間実行オペレーションや繰り返しオペレーションを実行する場合は、このプロパティを頻繁にチェックし、できるだけ早く処理を停止するためのシグナルとして使用する必要があります。

注: WorkManager は、onStop シグナルを受け取ったワーカーによって設定された Result を無視します。これは、ワーカーがすでに停止していると見なされるためです。