Android JetpackのWorkManagerを試す




## 公式ドキュメント
まず読む
https://developer.android.com/topic/libraries/architecture/workmanager/


```
WorkManager APIを使用すると、遅延タスク、非同期タスク、および実行するタイミングを簡単に指定できます。これらのAPIを使用すると、タスクを作成し、即時または適切なタイミングでWorkManagerに渡すことができます。

デバイスAPIレベルやアプリ状態などの要因に基づいて、タスクを実行するための適切な方法を選択します。アプリケーションの実行中にWorkManagerがいずれかのタスクを実行すると、WorkManagerはアプリケーションのプロセス内の新しいスレッドでタスクを実行できます。

あなたのアプリが実行されていない場合、ワークマネージャは、バックグラウンドタスクをスケジュールするための適切な方法を選択します-デバイスのAPIレベルに応じたとの依存関係を含め、ワークマネージャが使用する可能性のある JobScheduler、Firebase JobDispatcherを、かAlarmManager。
```

まとめると

- 遅延タスク、非同期タスクの実行に使える
- 実行タイミングを指定できる
- 新スレッドでタスクが実行される
- バックグラウンドで実行する
- APIレベルに応じて適切な方法を選択する
  - JobScheduler、Firebase JobDispatcher、AlarmManager


## 準備
AndroidプロジェクトにWorkManagerライブラリを追加

WorkManagerにはcompileSdkバージョン28以上が必要

https://developer.android.com/topic/libraries/architecture/adding-components#workmanager

```groovy:app/build.gradle
dependencies {
    // work managerを追加
    def work_version = "1.0.0-alpha09"
    implementation "android.arch.work:work-runtime:$work_version"
    implementation "android.arch.work:work-runtime-ktx:$work_version"

```

## 実装

実装する前に、公式ドキュメントを見てみる

https://developer.android.com/topic/libraries/architecture/workmanager/basics#concepts


- **Worker**
  - このクラスをextendし、実行する内容(タスク)を実装する
- **WorkRequest**
  - 作業の要求を表す
  - 自動生成された一意のIDがあり、このIDからキューに入れたタスクをキャンセルしたり、タスクの状態を見ることができる。
  - OneTimeWorkRequestまたはPeriodicWorkRequestを使用する
  - OneTimeWorkRequestは１回きりの実行、PeriodicWorkRequestは繰り返し実行
  - WorkRequestオブジェクトを作成するためのヘルパークラスがWorkRequest.Builder、PeriodicWorkRequest.Builderの２つある
- **WorkManager**
  - 制約が満たされた後に実行されることが保証されている作業を実行(エンキュー)する
  - APIレベル23以上は`JobScheduler`を使用する
  - APIレベル14-22はFirebase JobDispatcher、またはカスタムAlarmManager + BroadcastReceiver実装を使用する
  - 作業はバックグラウンドスレッドで実行される
- **WorkStatus**
  - 特定のタスクに関する情報が含まれている
  - `LiveData`でタスクの状態の観察、完了後の戻り値を取得できる

簡単にまとめると、
`Woker`を継承したクラスに動作を書き、
`WorkRequest`に制約を準備して、
`WorkManager`に実行をお願いし、
`WorkStatus`でタスクの状態管理/結果受取ができる。

## 標準

まずはシンプルに、ボタンを押したらログを出力するだけ

```kotlin:MainActivity
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //ボタンを押したら
        button1.setOnClickListener {
            startWorkManager()
        }
    }

    // WorkManagerを実行
    private fun startWorkManager() {
        val testWorker = OneTimeWorkRequestBuilder<TestWorker>().build()
        WorkManager.getInstance().enqueue(testWorker)
    }
}

// WorkManagerクラス
class TestWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    override fun doWork(): Result {
        // ここに処理内容を書く
        Log.d("MainActivity", "WorkManager Test")
        return Result.SUCCESS
    }
}
```

## 監視

監視してログを追加するなら、以下のようにする

```kotlin

        //タスクを監視
        WorkManager.getInstance().getStatusById(testWorker.id).observe(this, Observer {
            if (it == null) return@Observer
            Log.d("MainActivity:StatusById", it.toString())
        })
```

## 制約

以下の制約を作ってみる
- 充電中である
- 端末バッテリーが少なくない（どの程度あればいいのか？）

```kotlin
        //制約を作成
        val constraints = Constraints.Builder()
                .setRequiresCharging(true)      //充電中である
                .setRequiresBatteryNotLow(true) //バッテリーが少なくない
                .build()
        //worker requestを作成
        val testWorker = OneTimeWorkRequestBuilder<TestWorker>()
                .setConstraints(constraints)    //制約を追加
                .build()
```

OneTimeWorkRequestBuilderでビルド時に制約を追加してる

## キャンセル

キャンセルは不確定で、すでにタスクが実行中/完了している可能性もある

```kotlin
        WorkManager.getInstance().cancelWorkById(testWorker.id)
```

# 使用したコード

https://github.com/ikemura23/Android-Kotlin-Lab/tree/workmanager