LoginSignup
2
4

More than 3 years have passed since last update.

Android JetpackのWorkManagerの使い方

Posted at

Android JetpackのWorkManagerの使い方

JetpackはAndroidデベロッパーのために開発されたライブラリ、ツールなどのことを総称したものです。
今回はその中のWorkManagerという機能について説明します。

WorkManagerとは

APIの一つで、アプリが終了したり再起動しても延期できるタスクをスケジューリングする機能のようです。
定期的なサーバとの同期や、ログなどの送信に便利そうです。

下記が下位互換性
API 23 以上が搭載されたデバイスでは JobScheduler を使用
API 14~22 が搭載されたデバイスでは BroadcastReceiver と AlarmManager を組み合わせて使用

JobSchdulerなどは確かによく使われていましたが、これをさらにパッケージ化したものでしょうか。

ライブラリ追加

WorkManagerライブラリを使用するために、下記を追加してください。

build.gradle
def work_version = "2.3.4"
implementation "androidx.work:work-runtime:$work_version"
implementation "androidx.work:work-runtime-ktx:$work_version"

Worker

Workerでタスクを定義します。
doWorkメソッド内に実行したい処理を記述します。
そして、 Resultクラスでタスクの実行結果を受け取ることができます。

MyWorkManager.kt
class MyWorkManager(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {

    override fun doWork(): Result {
//    ここに実行したい処理を書く

        return Result.success()
    }
}

Resultクラスで返される状態は下記です

  • Result.success(): タスクが正常に終了したかどうか
  • Result.failure(): タスクが失敗したかどうか
  • Result.retry(): 後でタスクを再試行する必要があるかどうか

周期的実行

タスクの実行には一回だけの実行と、周期的に実行できるオプションがあります。
WorkerRequestを使います

  • OneTimeWorkRequest: 一回だけ
  • PeriodicWorkRequest: 定期的

例えば10秒ごとの周期的なタスクにする場合は下記のように作ります。

val periodic: Duration = Duration.ofSeconds(10L)
val uploadWorkRequest = PeriodicWorkRequestBuilder<MyWorkManager>(periodic ).build()

もしこんなエラーが出たら、ここをみてください。

Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper ‘-jvm-target’ option

その後、タスクをシステムにぶん投げます

WorkManager.getInstance(this).enqueue(uploadWorkRequest)

タスク実行タイミング

各タスクをデバイスの状態によって変えたい時に使えるのが、Constraintsクラスです。

  • setRequiredNetworkType: ネットワーク状態
  • setRequiresBatteryNotLow: 電池残量がたくさんある時
  • setRequiresCharging: 電源に接続されてる時
  • setRequiresDeviceIdle: デバイスがアイドル状態の時
  • setRequiresStorageNotLow: ストレージ容量がたくさんある時

下記は一例です

var constraints = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)
            .setRequiresBatteryNotLow(true)
            .setRequiresCharging(true)
            .setRequiresDeviceIdle(true)
            .setRequiresStorageNotLow(true)
            .build();

        val periodic: Duration = Duration.ofSeconds(10L)
        val uploadWorkRequest = PeriodicWorkRequestBuilder<MyWorkManager>(periodic)
            .setConstraints(constraints)
            .build();

タスクを10分後に実行したい時は、下記を設定します。

val periodic: Duration = Duration.ofSeconds(10L)
val uploadWorkRequest = PeriodicWorkRequestBuilder<MyWorkManager>(periodic)
            .setInitialDelay(10, TimeUnit.MINUTES)
            .build()

タスク再試行時間

タスクを再試行したい場合には、WorkerクラスからResult.retry()を返すようです。
また、バックオフという遅延時間を設定することで、タスクの増加時間をずらすことができるようです。

val periodic: Duration = Duration.ofSeconds(10L)
val uploadWorkRequest = PeriodicWorkRequestBuilder<MyWorkManager>(periodic)
            .setBackoffCriteria(
                    BackoffPolicy.LINEAR,
                    OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
                    TimeUnit.MILLISECONDS)
            .build()

Worker進捗・監視

Workerを進捗を設定するためにCoroutineWorkerクラスを使用します。
下記で0から100で進捗を設定することができます。


class ProgressWorker(context: Context, parameters: WorkerParameters) : CoroutineWorker(context, parameters) {

    companion object {
        const val Progress = "Progress"
        private const val delayDuration = 1L
    }

    override suspend fun doWork(): Result {
        val firstUpdate = workDataOf(Progress to 0)
        val lastUpdate = workDataOf(Progress to 100)
        setProgress(firstUpdate)
        delay(delayDuration)
        setProgress(lastUpdate)
        return Result.success()
    }
}

次にWorkerを監視するためには、observe機能を使用します。
observerにはLifecycleOwnerクラスを使用してタスクの状態を作成する必要があります。
getWorkInfoByIdLiveDataにはWorkerRequestのidを入れて下さい。


WorkManager.getInstance(applicationContext)
            .getWorkInfoByIdLiveData(uploadWorkRequest.id)
            .observe(observer, Observer { workInfo: WorkInfo? ->
                if (workInfo != null) {
                    val progress = workInfo.progress
                    val value = progress.getInt(Progress, 0)
                    // 進捗状態を使った処理
                }
            })

上記でタスクを実行しながら状態をユーザーにお知らせすることが可能です。

まとめ

他にもいろいろ機能を追加することが可能ですが、基本的な使い方はここで終わりです。
これを使えば今まで非同期通信のスケジューリングなどが簡単に作成することが可能になりました。
以上です

2
4
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
2
4