SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

一歩進んだAndroidアプリ開発ができる「Android Jetpack」入門

WorkManagerの発展的な使い方を解説 ──ワークチェイン、優先実行ワーカー、ワーカーの繰り返し実行

一歩進んだAndroidアプリ開発ができる「Android Jetpack」入門 第11回

  • X ポスト
  • このエントリーをはてなブックマークに追加

ワークチェインにおけるワーカーの状態

 ところで、第9回でも紹介したように、WorkManagerの実行状況は、Android Studioのバックグラウンドタスクインスペクタから確認できます。

 そして、この記事にもあるように、ワークチェインの状況もこのバックグラウンドタスクインスペクタで確認できます。図2は、試しに、リスト1や2のコードでワークチェインを実行させた際のバックグラウンドタスクインスペクタでの表示です。左側のグラフ表示では、まさに図1と同じ図が表示されています。

図2: バックグラウンドインスペクタでのワークチェインの表示
図2: バックグラウンドタスクインスペクタでのワークチェインの表示

 図2は、CreateCountWorkerの実行が終了し、ReceiveCountWorkerがキュー状態の時点でのキャプチャです。それぞれのワーカー名の前の(Succeeded)や(Enqueued)記号がそのことを示しています。

 FinishCountWorkerのは、Blockedという状態です。このFinishCountWorkerが選択された状態である図2の右側を見ると、State欄にBlockedという記述が見えます。

 このBlockedは、ワーカーの状態を紹介した第9回の図1には登場しておらず、ワークチェイン独特の状態です。このBlockedは、ワーカーそのものの保留状態であり、より上流のワーカーの終了を待っている状態です。

 そして、より上流のワーカーの処理が無事終了したSucceeded状態になって初めて、自身がEnqueued状態へと移行できるようになります(図3)。図2でReceiveCountWorkerがEnqueued状態なのは、上流のCreateCountWorkerがSucceededだからです。

図3: Enqueued状態へ移行できるのは上流のワーカーがSucceededの場合
図3: Enqueued状態へ移行できるのは上流のワーカーがSucceededの場合

 では、あるワーカーの実行が失敗、すなわち、Failed状態になった場合はどうなるかというと、それより下流のワーカーは自動的にFailed状態となります。図4は、ReceiveCountWorkerで処理が失敗し、Failed状態になった場合のバックグラウンドタスクインスペクタでの表示です。FinishCountWorkerが自動的にFailed状態になっているのが読み取れます。

図4: あるワーカーがFailed状態になるとそれ以降のワーカーも自動的にFailed状態に
図4: あるワーカーがFailed状態になるとそれ以降のワーカーも自動的にFailed状態に

ワークチェインでデータを渡す方法

 ワークチェインにおいて、上流のワーカーから下流のワーカーにデータを渡すこともできます。その際も、前回紹介したDataオブジェクトとそのビルダーを使います。

 例えば、ReceiveCountWorker側でループ処理を行う際に表示させるメッセージ文字列と、そのループ処理回数の生成処理をCreateCountWorkerで行い、ReceiveCountWorkerに渡すとします。その場合、CreateCountWorkerのdoWork()メソッド内のコードは、Javaではリスト3、Kotlinではリスト4のようになります。

リスト3:ワークチェインで次のワーカーにデータを渡す例(Java版)[CreateCountWorker.java]
Data.Builder dataBuilder = new Data.Builder();  // (1)
dataBuilder.putString("loopMsg", "こんにちは");  // (1)
dataBuilder.putInt("loopCount", loopCount);  // (1)
Data outputData = dataBuilder.build();  // (1)
return Result.success(outputData);  // (2)
リスト4:ワークチェインで次のワーカーにデータを渡す例(Kotlin版)[CreateCountWorker.kt]
val dataBuilder = Data.Builder()  // (1)
dataBuilder.putString("loopMsg", "こんにちは")  // (1)
dataBuilder.putInt("loopCount", loopCount)  // (1)
val outputData = dataBuilder.build()  // (1)
return Result.success(outputData)  // (2)

 このコードの(1)の部分は、前回のリスト1やリスト2とほぼ同じコードです。違いは、最後の変数名がinputDataからoutputDataに変わっただけです。リスト3やリスト4のコードのポイントは(2)です。

 これまで、ワーカー内の実行結果をリターンする値を生成するResult.success()などのメソッドには、引数は記述されていませんでした。これを、(2)のように、引数としてDateオブジェクトを渡すと、それがワークチェインの次のワーカーに渡されます。もちろん、次のワーカー(例えば今回でいえばReceiveCountWorker)内でのデータの受け取りコードは、前回のリスト3やリスト4と同じコードで取得できます。

並行処理ワークチェイン

 ワークチェインは同時に複数のワーカーを実行することもできます。例えば、図5はCountWithIdWorkerを3個実行したのちにFinishCountWithIdWorkerを実行したワークチェインを、グラフ表示させたキャプチャです。

図5: 並行処理ワークチェイン
図5: 並行処理ワークチェイン

 このような実行を行う場合のコードは、WorkManagerのbeginWith()メソッドにWorkRequestインスタンスのリストを渡します。上の例ですと、Javaではリスト5、Kotlinではリスト6のようになります。

リスト5:並行処理ワークチェインのコード例(Java版)[MainActivity.java]
List<OneTimeWorkRequest> workRequestList = Arrays.asList(countWithIdWork1Request, countWithIdWork2Request, countWithIdWork3Request);
workManager.beginWith(workRequestList).then(finishCountWithIdWorkRequest).enqueue();
リスト6:並行処理ワークチェインのコード例(Kotlin版)[MainActivity.kt]
val workRequestList = listOf(countWithIdWork1Request, countWithIdWork2Request, countWithIdWork3Request)
workManager.beginWith(workRequestList).then(finishCountWithIdWorkRequest).enqueue()

 ポイントは、CountWithIdWorkerのWorkRequestを、countWithIdWork1Request、countWithIdWork2Request、countWithIdWork3Requestの3個生成しておき、そのリストオブジェクトをbeginWith()メソッドの引数として渡しているところです。もちろん、これらはそれぞれ別の種類のワーカーでもかまいません。いずれにせよ、リストを渡すことで、渡されたワーカーは並行処理を行います。

 そして、すべてのワーカーの処理が成功した場合、下流のワーカー、例えば、リスト5やリスト6ならばthen()で渡されたFinishCountWithIdWorkerが実行されます。

並行処理における下流へのデータ渡し

 ただし、このような並行処理では注意が必要です。並行処理それぞれから下流のワーカーにデータが渡され、Dataオブジェクトのキーが同じ場合、最後に実行されたワーカーのデータにその内容が上書きされてしまいます。例えば、CountWithIdWorker内で、次のコードのように自身のUUIDを下流のワーカーに渡すとします。

dataBuilder.putString("id", id.toString());

 そうすると、Dataオブジェクトのキーidが重複します。この場合は、最後に実行したワーカーのUUIDしか下流は受け取ることができません。もちろんそれでかまわないケースもありますが、もし、それぞれのデータを受け取りたい場合は、それぞれのWorkRequestビルダーに対して、次のコードを実行します。

workRequestBuilder.setInputMerger(ArrayCreatingInputMerger.class);

 こうすることでキーが重複した場合、自動的に配列として格納してくれます。下流のワーカーでデータを受け取る場合は、次のコードを記述することで、各CountWithIdWorkerのUUID値を取り出すことができます。

String[] idList = inputData.getStringArray("id");

 なお、ここではJavaコードで記述していますが、Kotlinコードでも同じです。

次のページ
優先実行ワーカー

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
一歩進んだAndroidアプリ開発ができる「Android Jetpack」入門連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 齊藤 新三(サイトウ シンゾウ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook<個人紹介>WINGSプロジェクト所属のテクニカルライター。Web系製作会社のシステム部門、SI会社を経てフリーランスとして独立。屋号はSarva(サルヴァ)。HAL大阪の非常勤講師を兼務。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/20048 2024/08/30 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング