LoginSignup
9
9

More than 3 years have passed since last update.

Android Jetpack 初級 ( WorkManagerで、簡単定期実行 )

Last updated at Posted at 2019-06-17

WorkManager

1日に1回とか、何かを定期的に実行してほしい時があります。
バックグラウンドでユーザーの知らない間に、24時間に一回だけキャッシュの掃除をして欲しくて、手軽な形で使ってみました。

LifecycleLivedataTimber(なくてもいい)はすでに入っている前提です。

build.gradle
    // AAC (Work Manager)
    implementation "android.arch.work:work-runtime:1.0.1"
    implementation "android.arch.work:work-runtime-ktx:1.0.1"

定期実行してもらうための内容を以下の形で実装します。
WorkerParameters で、値を渡すことができます。

class PreferenceWorker(val context: Context, workerParameters: WorkerParameters) :
        Worker(context, workerParameters) {

    override fun doWork(): Result {

        //TODO: 定期実行してほしい処理をここで行う
        return Result.success()
    }
}

enqueueUniquePeriodicWorkは、一意の名前を付けられ、一つだけアクティブになり、TimeUnitで実行間隔を指定できます。
(最短は、PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS -> 15分)

以下は、トップレベル関数にしてもいい気はします。


class DailyWorkerUtil {

    companion object {

        //WorkManagerが動く上での制約。デバイスがWiFiに接続されていて、ストレージが不足していない場合にのみ機能する。
        private fun createConstraints() =
                Constraints.Builder() // WIFIに接続している場合
                        .setRequiredNetworkType(NetworkType.UNMETERED) //その他の値(NOT_REQUIRED、CONNECTED、NOT_ROAMING、METERED)
                        .setRequiresBatteryNotLow(true) //電池残量が少なくない場合
                        .setRequiresStorageNotLow(true) //ストレージが不足していない場合
                        .build()

        //24時間に一回動くようにリクエストを設定する
        private fun createWorkRequest() =
                PeriodicWorkRequestBuilder<PreferenceWorker>(24, TimeUnit.HOURS)
                        .setConstraints(createConstraints())
                        //作業をやり直す必要がある場合に備えてバックオフを設定する
                        .setBackoffCriteria(BackoffPolicy.LINEAR, PeriodicWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS)

        //ジョブのスタート関数。LiveDataを扱わない場合、LifeCycleOwnerは不要。必要な場合、コールバックを高階関数で設定しておく。
        fun startWork(lifecycleOwner: LifecycleOwner, callback: () -> Unit) {

            //入力データを設定します。バンドルのようなもの。
            val work = createWorkRequest().build()

            val workManager = WorkManager.getInstance()

            //ExistingPeriodicWorkPolicy.KEEPは、このジョブがすでに存在する場合は保持される
            workManager
                    .enqueueUniquePeriodicWork(
                            "Batch Work", ExistingPeriodicWorkPolicy.KEEP, work)

            //WorkManager自体の実行結果をLiveDataで、Observeする。
            workManager
                    .getWorkInfoByIdLiveData(work.id)
                    .observe(lifecycleOwner, Observer { workInfo ->
                        if (workInfo != null && workInfo.state == WorkInfo.State.SUCCEEDED) {
                            //定期実行終了後に、行いたい処理をここで行う
                            callback()
                            Timber.d("WorkManagerInfo:Success${work.id}:${workInfo.outputData}")
                        } else {
                            Timber.d("WorkManagerInfo:Failed${work.id}:${workInfo.state}")
                        }
                    })
        }
    }
}

PeriodicWorkRequestBuilder.setInputData(任意のデータ : Data) で、先ほどのWorkerParametersに値を渡すことができるので、そうしたい場合はstartWork()を呼ぶ際に

// TODO: Dataに値を渡してあげる
val work = createWorkRequest(Data.EMPTY).build()

などとしてあげましょう。

あとは、基底クラスで呼び出してあげるだけでアプリが存在する限り、自動的に指定の処理を行ってくれます。

MainActivity.kt
DailyWorkManager.startWork(lifecycleOwner = this , callback())

実行するだけでいいなら、もっとシンプルにできます。

ただ、端末のリソースや、設定した制約(Constraints)により、実行タイミングがずれ込んだりもするようなので、確実に実行してほしい場合は、もう少し考え込む必要がありそうです。

手軽に使いたい場合、簡単で、すごく便利ですね。

9
9
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
9
9