Android Kotlin基礎講座 09.2:WorkManager

タスク:バックグラウンドのworkerを作成する

コードをプロジェクトに追加していく前に、WorkManagerライブラリの以下のクラスについて知っておきましょう。

  • Worker
    このクラスはバックグラウンドで動作させたい実際の作業(タスク)を定義する場所です。このクラスを継承し、doWork()メソッドをオーバーライドします。doWork()メソッドはサーバーとのデータの同期や画像処理など、バックグラウンドで行わせたい処理のコードを書く場所です。このタスクでWorkerを実装していきます。
  • WorkRequest
    このクラスはバックグラウンドでworkerを動作させるためのリクエストを表すクラスです。WorkRequestを使って、workerのタスクをいつ、どのように実行させるかを設定します。後のタスクでWorkRequestを実装します。
  • WorkManager
    このクラスはWorkRequestのスケジューリング、実行を行います。WorkManagerは指定した制約を守りながら、システムリソース上の負荷を分散させてリクエストをスケジューリングします。後のタスクでWorkManagerを実装します。

ステップ1:Workerを作成

このタスクでは、バックグラウンドでDevByteの動画を読み込むためのWorkerを追加します。

  1. devByteviewerパッケージ内に、workという新規パッケージを作成してください。
  2. workパッケージ内に、RefreshDataWorkerという名前のKotlinクラスを作成してください。
  3. RefreshDataWorkerクラスにCoroutineWorkerクラスを継承させてください。contextとWorkerParametersをコンストラクタのパラメーターとして渡してください。
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {
}
  1. 抽象クラスエラーを解消するために、RefreshDataWorkerクラス内で、doWork()メソッドをオーバーライドしてください。
override suspend fun doWork(): Result {
  return Result.success()
}

suspend関数は後に停止、再開させられる関数です。suspend関数はメインスレッドをブロックしないで、ロングランニング操作を実行し、完了するのを待機させることができます。

ステップ2:doWork()を実装する

Workerクラス内のdoWork()メソッドはバックグラウンドスレッドで呼び出されます。このメソッドはタスクを同期的にこなし、ListenableWorker.Resultオブジェクトを返すべきです。AndroidシステムはWorkerにそれの執行を終え、ListenableWorker.Resultオブジェクトを返すための時間を最大10分間与えます。この時間が過ぎると、システムは強制的にWorkerを停止させます。

ListenableWorker.Resultオブジェクトを作成するためには、以下のstaticメソッドの一つを呼び出し、バックグラウンドタスクの完了状態を指定します。

  • Result.success()―タスクが正常に完了した場合に呼び出す。
  • Result.failure()―タスクが永久停止した状態で終了した場合に呼び出す。
  • Result.retry()―タスクが一時的に失敗し、リトライされるべき場合に呼び出す。

このタスクでは、doWork()メソッドを実装して、ネットワークからDevBytes動画のプレイリストを取得します。ネットワークからデータを取得するためには、VideosRepositoryクラス内の既存のメソッドを再利用できます。

  1. RefreshDataWorkerクラス内のdoWork()内に、VideosDatabaseオブジェクトとVideosRepositoryオブジェクトを作成・初期化してください。
override suspend fun doWork(): Result {
   val database = getDatabase(applicationContext)
   val repository = VideosRepository(database)

   return Result.success()
}
  1. RefreshDataWorkerクラス内、doWork()内のreturn文の上で、refreshVideos()メソッドをtryブロックの中で呼び出します。いつworkerが実行されているかをトラックするためのログを追加してください。
try {
   repository.refreshVideos( )
   Timber.d("Work request for sync is run")
   } catch (e: HttpException) {
   return Result.retry()
}

“Unresolved reference”エラーを解消するために、retrofit2.HttpExceptionをインポートしてください。

  1. 最終的なRefreshDataWorkerクラスは以下のようになります。
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
       CoroutineWorker(appContext, params) {

   override suspend fun doWork(): Result {
       val database = getDatabase(applicationContext)
       val repository = VideosRepository(database)
       try {
           repository.refreshVideos()
       } catch (e: HttpException) {
           return Result.retry()
       }
       return Result.success()
   }
}