LoginSignup
1
0

More than 3 years have passed since last update.

Sunflowerリポジトリで学ぶJetPack〜WorkManager編

Posted at

新型コロナの影響で自宅待機になってしまい、その間勉強するものとしてSunflowerリポジトリを
勧めてもらいました。

JetPackのライブラリのうち、今回はWorkManager編です

尚、引用しているソースは明記しているところ以外は、基本的には全てSunflowerのリポジトリのものです。 

環境

  • 確認時はAndroid Studioのバージョンは 3.6.2を使用しました
  • JetPackAndroidXライブラリを利用するのでCompile SDK28以上にする必要があります

そもそもWorkManagerってなに?

WorkManager API を使用すると、アプリが終了したりデバイスが再起動したりしても
実行することが要求される延期可能な非同期タスクのスケジュールを簡単に設定できます。

です!

WorkManagerの主な機能

機能

  • API 14 までの下位互換性
    • API 23 以上が搭載されたデバイスでは JobScheduler を使用
    • API 14~22 が搭載されたデバイスでは BroadcastReceiverAlarmManager を組み合わせて使用
  • ネットワークの可用性や充電ステータスなどの処理の制約を追加する
  • 非同期の 1 回限りのタスクや定期的なタスクのスケジュールを設定する
  • スケジュール設定されたタスクの監視と管理を行う
  • タスクを連携させる
  • アプリやデバイスが再起動してもタスクを確実に実行する
  • Doze モードなどの省電力機能に準拠する (公式より)

この中だと、APIレベルが低いものでも同じように使えるというところと、Dozeモードに対応しているのがいいですね
Dozeモード中にバックグラウンド処理が色々動かない、というのはAndroidあるあるだと思いますので。。。)

注意点

公式によると

WorkManager は、アプリが終了したりデバイスが再起動したりしても確実に実行する必要がある遅延可能なタスク(つまり、直ちに実行する必要がないタスク)を対象としています。次に例を示します。

  • ログやアナリティクスをバックエンド サービスに送信する
  • アプリデータをサーバーと定期的に同期する

つまり、確実に定周期で何かをする、などということには対応していない、ということですね。

利用する際に必要なこと

必要なことは下記の4点です

  1. 依存関係の記載
  2. バックグラウンドタスクの作成
  3. タスクを実行する方法とタイミングを設定とタスクをシステムに引き渡す処理

依存関係の記載

build.gradleに記載する内容

build.gradleには下記の依存関係の記載を行います。
(公式ドキュメントより)

build.gradle
    dependencies {
      def work_version = "2.3.1"

        // (Java only)
        implementation "androidx.work:work-runtime:$work_version"

        // Kotlin + coroutines
        implementation "androidx.work:work-runtime-ktx:$work_version"

        // optional - RxJava2 support
        implementation "androidx.work:work-rxjava2:$work_version"

        // optional - GCMNetworkManager support
        implementation "androidx.work:work-gcm:$work_version"

        // optional - Test helpers
        androidTestImplementation "androidx.work:work-testing:$work_version"
      }
  • 必須設定
    • Java
    • Kotlin + Coroutines
      • Javaで使う場合は、Javaの設定が、Kotlinで使う場合はKotlinの設定が必須となります。
  • オプション設定
    • RxJava2
    • GCMNetworkManager
    • Test helpers
      • これらはオプションなので、利用する場合は記載します。

Sunflowerリポジトリの場合

Sunflowerリポジトリの場合はどのようになっているかを見てみましょう

build.gradle
buildscript {
    // Define versions in a single place
    ext {
                    :
        // App dependencies
                    :
        workVersion = '2.1.0'
    }
                    :
}
app/build.gradle
dependencies {
                        :
    implementation "androidx.work:work-runtime-ktx:$rootProject.workVersion"
                        :
    // Testing dependencies
                        :
    androidTestImplementation "androidx.work:work-testing:$rootProject.workVersion"
                        :
}

Sunflowerリポジトリの場合は、下記設定となっていました。

  • Kotlinで利用しています
  • オプションはTest helpersを利用しています

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

それではSunflowerのバックグラウンドタスクを見てみましょう。

SeedDatabaseWorker.kt(part1)
class SeedDatabaseWorker(
    context: Context,
    workerParams: WorkerParameters
) : CoroutineWorker(context, workerParams) {
    override suspend fun doWork(): Result = coroutineScope {
                .
                .
                .
  • タスクは通常はWorkerクラスを使用して定義します
  • Workmanagerから提供されるバックグラウンドスレッドでdowork()メソッドが同期的に実行されます
  • ただし、SunflowerリポジトリではCoroutineWorkerを利用しています。
    • こちらはKotlinを使う際にオススメです
    • その場合doWork()メソッドはsuspend関数になり、サブスレッドで実行されます。
      • 実行するスレッドは、Workerクラスとは異なり、Configurationで指定されたExecutorではありません。
      • Dispatchers.Defaultで実行されます。
SeedDatabaseWorker.kt(part2)
        try {
            applicationContext.assets.open(PLANT_DATA_FILENAME).use { inputStream ->
                JsonReader(inputStream.reader()).use { jsonReader ->
                    val plantType = object : TypeToken<List<Plant>>() {}.type
                    val plantList: List<Plant> = Gson().fromJson(jsonReader, plantType)

                    val database = AppDatabase.getInstance(applicationContext)
                    database.plantDao().insertAll(plantList)

                    Result.success()
                }
            }
        } catch (ex: Exception) {
            Log.e(TAG, "Error seeding database", ex)
            Result.failure()
        }
    }

    companion object {
        private val TAG = SeedDatabaseWorker::class.java.simpleName
    }
}
  • 以降には、バックグラウンドタスクで実施する処理が記載されています。
    • ここではassets内のJsonファイルを読み込んだあと、パースしてデータベースに保存しています。
  • doWork()メソッドはResultの各メソッドを返します。
    • Result.success(): タスクが正常に終了したかどうか
    • Result.failure(): タスクが失敗したかどうか
    • Result.retry(): 後でタスクを再試行する必要があるかどうか
      • ここでは、データベースに保存ができれば正常終了、例外が発生した場合は失敗となっています。

タスク実行方法とタイミングを設定およびタスクをシステムに引き渡す処理

概要

  • Worker(CoroutineWorker)が作業単位を定義しますが、それに対し、WorkRequestは作業を実行する方法とタイミングを定義します。
  • タスクには1回実行するものと、定期的に実行されるものがあります
    • 1回のもの → OneTimeWorkRequest
    • 定期的なもの → PeriodicWorkRequest
  • WorkRequestを定義した後、WorkManagerenqueue()メソッドを使用してスケジュールを設定できます。

Sunflowerリポジトリ

AppDatabase.kt
        // Create and pre-populate the database. See this article for more details:
        // https://medium.com/google-developers/7-pro-tips-for-room-fbadea4bfbd1#4785
        private fun buildDatabase(context: Context): AppDatabase {
            return Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME)
                    .addCallback(object : RoomDatabase.Callback() {
                        override fun onCreate(db: SupportSQLiteDatabase) {
                            super.onCreate(db)
                            val request = OneTimeWorkRequestBuilder<SeedDatabaseWorker>().build()
                            WorkManager.getInstance(context).enqueue(request)
                        }
                    })
                    .build()
        }

Sunflowerリポジトリでは下記の処理になっています。

  • データベース作成時に一度だけ実施する処理OneTimeWorkRequestBuilderSeedDatabaseWorkerを実施している。

まとめ

  • バックグラウンドタスクの作成はWorkerクラスを作成する。Kotlinの場合はCoroutineWorkerがおすすめ
  • Workerクラスのdowork()メソッド内に実行する処理を書く。
  • タスクの実行の際、1回しか実施しないことは、OneTimeWorkRequest、定期的に実施するものはPeriodicWorkRequestで実行する。

以上です!

参考サイト

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0