WorkManager - Ki-Kobayashi/Android-Wiki GitHub Wiki
🟩 WorkManagerとは
https://developer.android.com/topic/libraries/architecture/workmanager/basics?hl=ja WorkManagerとは、
-
「時間がかかる処理」や「永続的な処理」などを、非同期でバックグラウンドで実行できる
-
アプリを閉じている時にも実行できる
-
タスクをスケジュールし、以下の3つの操作が可能になる
https://developer.android.com/topic/libraries/architecture/workmanager?hl=ja#types- 即時(1回限り)
- 長時間実行(1回限り or 定期的)
- 設定したスケジュール、条件を満たしたとき実行させられる(1回限り or 定期的)
-
スケジュールされた処理は、内部のSQLite データベースに保存される
-
Doze モードなどの省電力機能やベスト プラクティスに従うため、電力消費を気にする必要なし
.
🟡 条件とは
以下のような条件を満たしたときだけ実行するときにも、WorkManagerは使える
- 「Wifiに繋いでる時だけ」「保存容量が○○GB以上の時」「充電○%以上」のような条件を指定してその条件になるまで待ってから実行
- 並列実行と順次実行
🟡 具体例
在庫確認に使用するアプリの場合、在庫数の最新の値を定期的に取得する必要がある
.
🟩 APIレベルが23未満の場合
WorkManagerではなく、「BroadcastReceiver」+「AlarmManager」の組み合わせを利用する必要がある
.
🟩 WorkManagerの作成手順
- WorkerManagerを導入する
- Worker のサブクラス作成
- Work リクエストの作成 + 実行
🟡1:WorkManagerの導入
https://developer.android.com/topic/libraries/architecture/workmanager/basics?hl=ja
💎app / build.gradle
dependencies {
val work_version = "2.8.0"
// Kotlin + coroutines
implementation("androidx.work:work-runtime-ktx:$work_version")
.
🟡2:WorkManagerのサブクラスの作成
https://developer.android.com/topic/libraries/architecture/workmanager/basics?hl=ja#define_the_work
💎任意のクラス名で作成
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters
class UploadWorker(context: Context, params: WorkerParameters): Worker(context, params) {
override fun doWork(): Result {
return try {
// 💡ここで定期/条件マッチ時などに実行させたい処理をかく
for (i in 0..60) {
Log.d("AAAA", "uploading... $i")
}
Result.success()
} catch (e: Exception) {
Result.failure() 👈忘れずに
}
}
}
.
🟡3: Work リクエストの作成 + 実行
.
💎 1回限り or 定期的
リクエスト作成時は、以下を使い分ける
- 1回限り: OneTimeWorkRequest
- 定期的:PeriodicWorkRequest
.
💎設定したいクラスで作成(書き方2種)
📚 1つ目の書き方
private fun setOneTimeWorkRequest() {
// リクエストの作成
val uploadWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>().build() 👈 build()忘れずに!
// WorkRequest を WorkManager に送信する
WorkManager.getInstance(applicationContext).enqueue(uploadWorkRequest)
}
.
📚 2つ目の書き方
private fun setOneTimeWorkRequest() {
// リクエストの作成
val uploadWorkRequest = OneTimeWorkRequest.Builder(UploadWorker::class.java).build()👈 build()忘れずに!
// WorkRequest を WorkManager に送信する
WorkManager.getInstance(applicationContext).enqueue(uploadWorkRequest)
}
.
💎WorkManagerの実行制約(条件)を付ける方法
🛑ネット状況を確認するには、マニフェストファイルに下記二つの権限を追加しておく
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
.
📚 WorkManagerの実行制約(条件)付きリクエストの作成
private fun setOneTimeWorkRequest() {
val workManager = WorkManager.getInstance(applicationContext)
// 💡手順1:実行条件(制約)の設定
val constraints = Constraints.Builder()
.setRequiresCharging(true) // 💡充電中である
.setRequiredNetworkType(NetworkType.CONNECTED) // 💡ネット接続中である
.build()
val uploadWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
.setConstraints(constraints) // 💡手順2:リクエストにセット
.build()
// 💡タスクの実行
workManager.enqueue(uploadWorkRequest)
// WorkManagerの状態を監視する
workManager.getWorkInfoByIdLiveData(uploadWorkRequest.id)
.observe(this, Observer {
binding.textWork.text = it.state.name
})
}
.
💎WorkRequestで設定できるもの
https://developer.android.com/topic/libraries/architecture/workmanager/how-to/define-work?hl=ja
- 1回限りの処理と繰り返し処理のスケジュールを設定する
- 処理の制約を設定する(Wi-Fi や充電の必要など)
- 処理の実行の遅延が最小限になるよう保証する
- 再試行とバックオフの戦略を設定する
- 入力データを処理に渡す
- タグを使用して関連する処理をグループ化する
.
🟡2-2:WorkManagerの状態を監視して取得
💡コード内の「this」は、ライフサイクルオーナー(Activityの場合はthisを使う)
// WorkManagerの状態を監視する
workManager.getWorkInfoByIdLiveData(uploadWorkRequest.id)
.observe(this, Observer {
binding.textWork.text = it.state.name
})
.
💎WorkInfoで得られる状態
- Blocked: まだ作業できない状態
- Enqueued:実行可能状態
- Running:実行中
- Succeed:作業成功
.
🟩 Workerのサブクラスに値を渡す方法
https://developer.android.com/topic/libraries/architecture/workmanager/how-to/define-work?hl=ja
Workerのサブクラスに値を渡すには、WorkerManagerのインスタンスを作成する箇所と、受け手であるサブクラスで設定が必要
以下の2種によって、設定方法が異なる
- 🟡 呼び出し側 から WorkManager(入力データを渡す)
- 🟣 WorkManager から 呼び出し側 (出力データを返す)
.
🟡【呼び出し側 から WorkManager】送り手の設定
「💎」箇所を参照
private fun setOneTimeWorkRequest() {
val workManager = WorkManager.getInstance(applicationContext)
// 💎:WorkerManagerに渡したい値を生成(※Data: workパッケージのもの)
val data: Data = Data.Builder()
.putInt(KEY_COUNT, 250)
.build()
// 🌟:実行条件(制約)の設定
val constraints = Constraints.Builder()
.setRequiresCharging(true) // 充電中である
.setRequiredNetworkType(NetworkType.CONNECTED) // ネット接続中である
.build()
val uploadWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>()
.setInputData(data) // 💎:WorkerManager渡したいデータのセット(WorkerManagerサブクラスで受け取る処理も追加すること)
.setConstraints(constraints) // 🌟:リクエストにセット
.build()
// タスクの実行
workManager.enqueue(uploadWorkRequest)
// WorkManagerの状態を監視する
workManager.getWorkInfoByIdLiveData(uploadWorkRequest.id)
.observe(this, Observer {
binding.textWork.text = it.state.name
})
}
companion object {
const val KEY_COUNT = "key_count"
}
.
🟡【呼び出し側 から WorkManager】受け手の設定
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters
class UploadWorker(context: Context, params: WorkerParameters): Worker(context, params) {
override fun doWork(): Result {
return try {
// 💎:WorkManagerのインスタンス生成箇所から、データを受け取る
val count = inputData.getInt(MainActivity.KEY_COUNT, 0)
for (i in 0..count) {
Log.d("AAAA", "uploading... $i")
}
Result.success()
} catch (e: Exception) {
Result.failure()
}
}
}
.
🟣【WorkManager から 呼び出し側】送り手の設定
「🟣」箇所を参照
import android.content.Context
import android.util.Log
import androidx.work.Data
import androidx.work.Worker
import androidx.work.WorkerParameters
import java.text.SimpleDateFormat
import java.util.Date
class UploadWorker(context: Context, params: WorkerParameters): Worker(context, params) {
override fun doWork(): Result {
return try {
// 💎:WorkManagerのインスタンス生成箇所から、データを受け取る
val count = inputData.getInt(MainActivity.KEY_COUNT, 0)
for (i in 0..count) {
Log.d("AAAA", "uploading... $i")
}
// 🟣処理完了時刻を呼び出し側に返す
val sdf = SimpleDateFormat("yyyy/M/dd hh:mm:ss")
val currentDateTime = sdf.format(Date())
// 🟣返却データの生成
val outPutData = Data.Builder()
.putString(KEY_WORKER, currentDateTime)
.build()
Result.success(outPutData) // 🟣succeess にセットして返す(呼び出し元にも、受け取る処理を追加すること)
} catch (e: Exception) {
Result.failure()
}
}
companion object{
const val KEY_WORKER = "key_worker"
}
}
.
🟣【WorkManager から 呼び出し側】受け手の設定
「🟣」箇所を参照
// WorkManagerの状態を監視する
workManager.getWorkInfoByIdLiveData(uploadWorkRequest.id)
.observe(this, Observer {
binding.textWork.text = it.state.name
//🟣WorkManager側からの返却値はここで受け取る + Toast表示
//🟣処理が完了していないと、データもないため、必ずチェックする
if (it.state.isFinished) {
val message = it.outputData.getString(UploadWorker.KEY_WORKER)
Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT)
}
})
.
🟩
🟡
.
🟩
🟡
.
🟩
🟡
.
🟩
🟡
.
🟩
🟡
.
🟩
🟡
.