いまさらWorkManager〜基本編⑤（Workerクラスにデータを渡す）〜

# はじめに
この[記事](https://qiita.com/naoi/items/e08f081fe42ef3694046)で説明した通り、様々な機能を活用していきましょう。
Workerクラスに何かしらの情報（データ）を引き渡したいといったこともあるでしょう。
その様な場合にも対応する機能が存在します。
今回はデータの渡し方を説明します。

# 動作環境
この記事の動作環境は以下のとおりです。

* Android Studio：3.3
* Kotln：1.3.11
* Open JDK:1.8
* compileSdkVersion：28
* targetSdkVersion：28
* minSdkVersion：19

# 目標
Workerクラスにデータを渡す！

# 完成イメージ
この記事では、下記のアプリで動作確認を行っています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99960/3b56a377-7c35-edcc-16fe-4bd44aa36bd4.gif" width="30%" >


# 概要
Workerにデータを渡すにはWorkRequestに格納して渡すことになります。
詳細な説明の前にイメージを確認しておきます。

![Dataの渡し方.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99960/ccf0f295-5d72-362c-fffc-b5334553a24c.png)


# 説明
## DataクラスとData.Builderクラス
Workerクラスにデータを渡すにはDataクラスを利用します。
名前が一般的すぎて、更に同じ名前のクラスが多いため、パッケージも含めて覚える必要があります。
完全クラス名は「 **androidx.work.Data** 」です。
内部的にMapを保持しており、そのMapに格納したデータがWorkerクラスを継承したクラスに渡されます。

Dataクラスのオブジェクトを生成するには、Data.Builderクラスを利用します。
BuilderクラスのsetXXXメソッドを呼び出しデータを格納していきます。

実際の実装例を確認すると理解が早まると思います。

```kotlin
val data = Data.Builder().apply {
    putString("message", editInput.text.toString())
}.build()
```

## WorkRequestへの格納
生成したDataクラスのオブジェクトを格納するには、WorkRequestのsetInputDataメソッドを呼び出します。

Dataクラス同様に、実際の実装例を確認すると理解が早まると思います。

```kotlin
val request = OneTimeWorkRequestBuilder<MyWorker>().apply {
    setInputData(data)
}.build()
```

## Workerクラス内でDataの取得と値の取得
Dataを受け取るには、Workerクラスを継承したクラス内でgetinputDataメソッドを呼び出します。Kotlinの場合は、プロパティのアクセスでgetterメソッドを呼び出すことなく、変数のようにアクセス可能です。

取得したDataから格納されている値を取得するには、getXXXメソッドに格納したときのキーを指定して取得します。
コードで確認してみましょう。

```kotlin
inputData.getString("message")
```

# 実装コード
この記事で動作確認したコードをすべて掲載します。
AndroidManifest.xmlはテンプレートで作成された状態から変更していないため、省略します。

```groovy:build.gradle

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "jp.co.casareal.workmanagersenddata"
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    def work_version = "1.0.0"

    implementation "android.arch.work:work-runtime-ktx:$work_version"

}
```

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:inputType="textPersonName"
            android:text="Casareal"
            android:ems="10"
            android:id="@+id/editInput" android:layout_marginTop="8dp"
            app:layout_constraintTop_toTopOf="parent" android:layout_marginEnd="8dp"
            app:layout_constraintEnd_toEndOf="parent" android:layout_marginStart="8dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toTopOf="@+id/btnStart"/>
    <Button
            android:text="WorkStart"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/btnStart"
            app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent"
            android:layout_marginStart="8dp" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
            app:layout_constraintTop_toBottomOf="@+id/editInput"
            android:layout_marginBottom="8dp"/>
</android.support.constraint.ConstraintLayout>
```

```kotlin:MyWoker.kt
package jp.co.casareal.workmanagersenddata

import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import android.support.v4.app.NotificationCompat
import androidx.work.Worker
import androidx.work.WorkerParameters
import java.text.SimpleDateFormat

class MyWorker(cxt: Context, params: WorkerParameters) : Worker(cxt, params) {
    val notificationManager =
        applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    // カテゴリー名（通知設定画面に表示される情報）
    val name = "通知のタイトル的情報を設定"
    // システムに登録するChannelのID
    val id = "casareal_chanel"
    // 通知の詳細情報（通知設定画面に表示される情報）
    val notifyDescription = "この通知の詳細情報を設定します"

    private val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")

    companion object {
        var nid = 1;
    }


    init {
        // Channelの取得と生成
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            notificationManager.getNotificationChannel(id) == null
            val mChannel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_HIGH)
            mChannel.apply {
                description = notifyDescription
            }
            notificationManager.createNotificationChannel(mChannel)
        }
    }

    override fun doWork(): Result {


        val notification = NotificationCompat.Builder(applicationContext, id).apply {
            setContentText("受け取ったメッセージ:${inputData.getString("message")}")
            setSmallIcon(R.drawable.ic_launcher_background)
        }

        notificationManager.notify(MyWorker.nid, notification.build())

        return Result.success()
    }
}
```

```kotlin:MainActivity.kt
package jp.co.casareal.workmanagersenddata

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import androidx.work.Data
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private val manager = WorkManager.getInstance()

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


        btnStart.setOnClickListener {

            val request = OneTimeWorkRequestBuilder<MyWorker>().apply {
                val data = Data.Builder().apply {
                    putString("message", editInput.text.toString())
                }.build()
                setInputData(data)
            }.build()

            manager.enqueue(request)
        }
    }
}
```

# まとめ
この記事ではDataを渡すだけなので、短めですが以下が理解できました。

* Workerクラスにデータを渡すときはandroidx.work.Dataオブジェクトを生成する
* DataはWorkRequestに格納する
* WorkerクラスでDataを取得するにはgetInputDataメソッドを呼び出す