処理チェーンの作成

WorkManager を使用すると、複数依存タスクの指定と実行順序の定義を行う処理チェーンを作成し、キューに登録できます。この機能は、複数のタスクを特定の順序で実行する必要がある場合に特に便利です。

処理チェーンを作成するには、それぞれ WorkContinuation のインスタンスを返す WorkManager.beginWith(OneTimeWorkRequest) または WorkManager.beginWith(List<OneTimeWorkRequest>) を使用します。

さらに WorkContinuation を使用し、then(OneTimeWorkRequest) または then(List<OneTimeWorkRequest>) を呼び出すと、依存関係にある OneTimeWorkRequest インスタンスを追加できます。

WorkContinuation.then(...) は、呼び出されるたびに新しい WorkContinuation のインスタンスを返します。OneTimeWorkRequest インスタンスの List を追加すると、これらのリクエストを並行して実行できる可能性があります。

最後に、WorkContinuation.enqueue() メソッドを使用して、WorkContinuation のチェーンに対して enqueue() を実行します。

次のような例を考えてみましょう。この例では、3 つの異なるワーカー処理を実行するように設定されています(同時に実行することも可能)。これらのワーカーの結果は結合され、キャッシュ ワーカー処理に渡されます。最後に、その処理の出力がアップロード ワーカーに渡され、その結果がリモート サーバーにアップロードされます。

Kotlin

WorkManager.getInstance(myContext)
   // Candidates to run in parallel
   .beginWith(listOf(plantName1, plantName2, plantName3))
   // Dependent work (only runs after all previous work in chain)
   .then(cache)
   .then(upload)
   // Call enqueue to kick things off
   .enqueue()

Java

WorkManager.getInstance(myContext)
   // Candidates to run in parallel
   .beginWith(Arrays.asList(plantName1, plantName2, plantName3))
   // Dependent work (only runs after all previous work in chain)
   .then(cache)
   .then(upload)
   // Call enqueue to kick things off
   .enqueue();

入力マージツール

OneTimeWorkRequest インスタンスを連結すると、親の処理リクエストの出力が子への入力として渡されます。したがって、上の例では、plantName1plantName2plantName3 の出力が cache リクエストへの入力として渡されています。

WorkManager では、複数の親の処理リクエストからの入力を管理するために InputMerger が使用されます。

WorkManager が提供する InputMerger には次の 2 種類があります。

  • OverwritingInputMerger: あらゆる入力のすべてのキーを出力に追加します。競合が発生すると、以前に設定したキーは上書きされます。

  • ArrayCreatingInputMerger: 入力をマージして、必要に応じて配列を作成します。

より具体的なユースケースがある場合は、InputMerger をサブクラス化することで、独自の入力マージツールを作成できます。

OverwritingInputMerger

OverwritingInputMerger は、デフォルトのマージメソッドです。マージ中にキーの競合が発生すると、キーの最新値により、結果の出力データ内の以前のバージョンが上書きされます。

たとえば、入力する植物名にそれぞれ個別の変数名("plantName1""plantName2""plantName3")と一致するキーがある場合、cache ワーカーに渡されるデータには 3 つの Key-Value ペアが含まれます。

3 つの処理が、チェーンの次の処理に異なる出力を渡している図。3 つの出力のキーがすべて異なるため、次の処理は 3 つの Key-Value ペアを受け取ります。

競合が発生すると、最後の出力となるワーカーが優先されて cache に渡されます。

3 つの処理が、チェーンの次の処理に出力を渡している図。この場合、2 つの処理が同じキーで出力を生成します。その結果、次の処理は 2 つの Key-Value ペアを受け取り、競合する出力の 1 つが破棄されます。

WorkRequest は並行して実行されるため、実行順序は保証されません。上の例では、plantName1 は最後に書き込まれた値に応じて、"tulip" または "elm" のいずれかの値を保持します。キーが競合する可能性があり、すべての出力データをマージで保持する必要がある場合は、ArrayCreatingInputMerger を使用することをおすすめします。

ArrayCreatingInputMerger

上の例ですべての植物名ワーカーからの出力を保持するには、ArrayCreatingInputMerger を使用します。

Kotlin

val cache: OneTimeWorkRequest = OneTimeWorkRequestBuilder<PlantWorker>()
   .setInputMerger(ArrayCreatingInputMerger::class)
   .setConstraints(constraints)
   .build()

Java

OneTimeWorkRequest cache = new OneTimeWorkRequest.Builder(PlantWorker.class)
       .setInputMerger(ArrayCreatingInputMerger.class)
       .setConstraints(constraints)
       .build();

ArrayCreatingInputMerger は、各キーと 1 つの配列をペアにします。各キーが一意である場合、それぞれ要素を 1 つずつ持つ配列になります。

3 つの処理が、チェーンの次の処理に異なる出力を渡している図。次の処理には、出力キーごとに 1 つずつ計 3 つの配列が渡されます。各配列のメンバーはそれぞれ 1 つずつです。

キーの競合が発生すると、同じキーに対する値は 1 つの配列にまとめられます。

3 つの処理が、チェーンの次の処理に出力を渡している図。この場合、2 つの処理が同じキーで出力を生成します。次の処理には、キーごとに 1 つずつ計 2 つの配列が渡されます。配列の 1 つには、2 つのメンバーが含まれています。これは、このキーを持つ出力が 2 つあったためです。

チェーンの作成と処理のステータス

OneTimeWorkRequest のチェーンは、処理が正常に完了すれば(Result.success() を返せば)順番に実行されます。実行中に処理リクエストが失敗するかキャンセルされると、依存する処理リクエストに影響が生じます。

ある処理リクエスト チェーンで最初の OneTimeWorkRequest がキューに登録されると、後続のすべての処理リクエストは、最初の処理リクエストが完了するまでブロックされます。

処理チェーンを示す図。最初の処理がキューに登録されると、すべての後続処理は、最初の処理が完了するまでブロックされます。

最初の処理リクエストは、キューに登録されて処理の制約をすべて満たすと開始されます。ルートの OneTimeWorkRequest または List<OneTimeWorkRequest> で処理が正常に完了した場合(Result.success() を返した場合)、依存する処理リクエストの次のセットがキューに登録されます。

処理チェーンを示す図。最初の処理が成功し、直後の 2 つの処理がキューに登録されます。残りの処理は、先行処理が完了するまでブロックされます。

それぞれの処理リクエストが正常に完了している限り、チェーン内のすべての処理が完了するまで、同様にして残りの処理リクエストが処理されます。これは最もシンプルで多くの場合理想的なケースですが、エラーが発生した場合それに対処することも同様に重要です。

ワーカーが処理リクエストを処理している間にエラーが発生した場合は、定義したバックオフ ポリシーに従ってリクエストを再試行できます。チェーン内のあるリクエストを再試行するということは、そのリクエストのみを同じ入力データを使用して再試行するということです。並行して実行されている処理は影響を受けません。

処理チェーンを示す図。処理の 1 つが失敗しましたが、バックオフ ポリシーが定義されていました。この処理は、一定の時間が経過した後に再実行されます。チェーン内の次の処理は、この処理が正常に完了するまでブロックされます。

カスタム再試行戦略の定義の詳細については、再試行とバックオフ ポリシーをご覧ください。

再試行ポリシーが定義されていない場合、再試行回数上限に達した場合、または OneTimeWorkRequestResult.failure() を返すことが想定される状態に達した場合は、その処理リクエストとそれに依存するすべての処理リクエストが FAILED. とマークされます。

処理チェーンを示す図。1 つの処理が失敗し、再試行できません。その結果、チェーン内のすべての後続処理も失敗します。

OneTimeWorkRequest がキャンセルされたときにも同じロジックが適用されます。依存する処理リクエストも CANCELLED とマークされ、処理は実行されません。

処理チェーンを示す図。1 つの処理がキャンセルされました。その結果、チェーン内のすべての後続処理もキャンセルされます。

処理リクエストが失敗したかキャンセルされたチェーンにさらに処理リクエストを追加すると、新たに追加された処理リクエストも FAILED または CANCELLED とマークされます。既存のチェーンの処理を拡張する場合は、ExistingWorkPolicyAPPEND_OR_REPLACE をご覧ください。

処理リクエスト チェーンを作成する際は、依存する処理リクエストで再試行ポリシーを定義して、処理がタイムリーに完了するようにします。処理リクエストの失敗により、チェーンが不完全になったり、予期しない状態になったりすることがあります。

詳しくは、処理のキャンセルと中止をご覧ください。