WorkManagerの基本の使い方
では、早速、実際にコードを交えながら、WorkManagerの使い方の基本を紹介していきます。
WorkManagerの使い方手順
WorkManagerを利用する場合は、以下の手順となります。
- ワーカーの用意
- WorkRequestの用意
- WorkManagerへのWorkRequestの登録
以下、順にコードを交えて紹介していきます。ただし、これらのコードを記述するプロジェクト、すなわち、WorkManagerを利用するプロジェクトでは、あらかじめその設定を行っておく必要があります。これは、build.gradle.kts(:app)ファイルのdependenciesブロックへの、リスト1の2行のコードの追記です。なお、work_versionのバージョン番号は、原稿執筆時点での番号です。最新バージョンに関しては、こちらのページを参照してください。
dependencies { val work_version = "2.9.0" implementation("androidx.work:work-runtime:$work_version") : }
1. ワーカーの用意
この手順は、ワーカークラスを用意することです。このワーカークラスでは、実際にバックグラウンドで行いたい処理を記述します。例えば、Javaではリスト2のようなクラスです。
public class CountUpWorker extends Worker { // (1) public CountUpWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { // (2) super(context, workerParams); // (3) } @NonNull @Override public Result doWork() { // (4) : return Result.success(); // (5) } }
ワーカークラスを作成する場合、まず、(1)のように、Workerクラスを継承して作ります。このWorkerクラスを継承すると、必ず以下の2点を行わないとコンパイルエラーとなります。
- コンストラクタの定義
- doWork()の実装
以下、順に説明します。
まず、Workerクラスのコンストラクタには引数が設定されているため、Workerクラスを継承したクラスでは、(2)のようにコンストラクタを定義し、その中で(3)のようにsuper()を実行する必要があります。(2)のコンストラクタの引数定義は、(3)のsuper()に渡す2個の引数をそのまま定義します。これらの引数は、ワーカーを実行する際に内部で利用されるため、特別なコーディングは不要です。
次に、doWork()の実装に関してです。Workerクラスは抽象クラスとなっており、このdoWork()が抽象メソッドとなっています。そのため、継承すると必ず(4)のdoWork()メソッドを実装する必要があります。そして、このメソッド内に、バックグラウンドで行いたい処理を記述し、最終的に(5)のResult.success()をリターンします。この意味については、次節で紹介します。
このワーカークラスをKotlinで記述した例は、リスト3のようになります。リスト2のコードをそのままKotlinに置き換えただけとなるので、特に解説は不要でしょう。
class CountUpWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { override fun doWork(): Result { : return Result.success(); } }
2. WorkRequestの用意
バックグラウンド処理が記述されたワーカークラスが用意されたので、このワーカークラスを実際に起動してバックグラウンド処理を行っていきます。といっても、アクティビティやフラグメント、あるいは、ViewModelやリポジトリなどのUIスレッドオブジェクト内で、このワーカークラスをnewしてdoWork()メソッドを実行するわけではありません。代わりに行うのが、先の手順の2と3です。ここでは、そのうち手順の2のWorkRequestの用意を紹介します。基本コードは、Javaならばリスト4、Kotlinならばリスト5の1行だけです。
WorkRequest workRequest = OneTimeWorkRequest.from(CountUpWorker.class);
val workRequest = OneTimeWorkRequest.from(CountUpWorker::class.java)
このコードの通り、OneTimeWorkRequestクラスのstaticメソッドであるfrom()を実行するだけで、WorkRequestが用意できます。その際、引数として、実行したいワーカークラスを渡します。
ただし、ここで紹介した方法は、ごく基本中の基本であり、実際には、このWorkRequestを用意する手順にさまざまなバリエーションがあります。それらに関して、次節以降紹介していきます。
3. WorkManagerへのWorkRequestの登録
最後の手順が、WorkManagerへのWorkRequestの登録であり、Javaならばリスト6、Kotlinならばリスト7のコードとなります。
WorkManager workManager = WorkManager.getInstance(MainActivity.this); workManager.enqueue(workRequest);
val workManager = WorkManager.getInstance(this@MainActivity) workManager.enqueue(workRequest)
これらのコードは、最終的にWorkManagerオブジェクトのenqueue()メソッドを実行するコードです。その際、手順2で用意したWorkRequestオブジェクトを渡します。
そのために、リスト6もリスト7も、1行目でWorkManagerインスタンスを取得しています。これは、WorkManagerのstaticメソッドのgetInstance()を実行します。その際、コンテキストを渡します。
もちろん、リスト6もリスト7も可読性を重視し、2行でコードを記述していますが、以下のように1行でコードを記述してもかまいません。
WorkManager.getInstance(MainActivity.this).workManager.enqueue(workRequest);
このコードが実行された段階で、ワーカーオブジェクトがWorkManagerに登録され、その後は、WorkManagerがOSなどのさまざまな状況を確認しながら、適切なタイミングで登録されたワーカーオブジェクトのdoWork()メソッドが実行されます。
なお、これらのワーカーの実行は、すべてバックグラウンドで行われるため、原則、その実行状況は確認できませんし、確認する必要はありません。ただし、開発段階では、デバッグの関係上、確認したい場合もあります。その場合は、こちらにあるように、Android Studioのバックグラウンドタスクインスペクタから確認できます。
Work StatesとdoWork()の戻り値
WorkManagerの基本を紹介したところで、ワーカーのコードについて解説していないところ、すなわち、リスト2の(5)のdoWork()も戻り値の意味に関して説明していきます。
ワーカーの状態を表すWork States
doWork()の戻り値の意味を理解するには、Work Statesを理解する必要があります。これは、ワーカーの処理の状態を表します。この状態を解説するために、Androidの公式ドキュメントには、図1が掲載されています。
リスト6やリスト7のコードでWorkManagerのenqueue()メソッドが実行された時点で、WorkRequestに登録されているワーカーはENQUEUED状態になります。そして、WorkRequestに設定された内容に応じて、適切なタイミングでワーカーが実行され、RUNNINGの状態になります。なお、リスト4やリスト5のfrom()メソッドにより生成されたWorkRequestは、全く設定が行われていない、デフォルトのWorkRequestとなります。
RUNNINGの状態のワーカーは、終了状態にならない限りは、ENQUEUED状態に戻されます。これをリトライ(RETRY)といいます。では、終了状態とは何かというと、図1の右側3個、すなわち、処理が成功したSUCCEEDED、処理が失敗したFAILED、処理をキャンセルしたCANCELLEDです。なお、キャンセルに関しては、図1の矢印の通り、ENQUEUED状態から直接CANCELLEDに移行することが可能であり、いずれにせよ、キャンセル処理が行われた場合です。
doWork()の戻り値
一方、SUCCEEDEDとFAILED、さらに、RETRYに関しては、doWork()の戻り値として指定できます。この仕組みを利用して、doWork()メソッド内は、リスト8のようなコードパターンとすることができます。
public Result doWork() { : Result returnVal = Result.success(); // (1) if(処理を再実行したい場合) { returnVal = Result.retry(); // (2) } else if(処理を失敗としたい場合) { returnVal = Result.failure(); // (3) } return returnVal; }
ポイントは、リスト2の(5)で紹介したResult.success()だけではなく、このワーカーを再実行したい場合は、リスト8の(2)のように、Result.retry()を戻り値とできることです。同様に、このワーカーの実行失敗としたい場合は、(3)のResult.failure()を戻り値とできます。もちろん、必ずResultオブジェクトを戻り値としなければならないため、リスト8のコードパターンでは、(1)のように、デフォルトでResult.success()を戻り値とするようにしています。なお、ソースコードの掲載は割愛しますが、Kotlinでも同様のコードパターンとします。