Androidで、ktor + coroutines で通信をする。

Android で、通信処理を実装しようとすると、[retrofit](https://github.com/square/retrofit) が1番最初に思いつきます。
ただ、選択肢は多い方がいいと思いますので、マルチプラットフォームで実装出来る [ktor](https://github.com/ktorio/ktor) を紹介したいと思います。

### gradle

* ktor

ktor は、マルチプラットフォーム対応なので、通信ライブラリーも選択可能です。
Androidの場合、OkHttp, Android があります。
今回は、OkHttp にします。
また、Json も同様に Gson, Jackson, Kotlinx.Serialization が選択が出来ます。
今回は、Kotlinx.Serialization にします。

```gradle
dependencies {
    implementation "io.ktor:ktor-client-core:1.3.1"
    implementation "io.ktor:ktor-client-android:1.3.1"
    implementation "io.ktor:ktor-client-okhttp:1.3.1"
    implementation "io.ktor:ktor-client-serialization-jvm:1.3.1"
}
```

* coroutines

```gradle
dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3"
}
```

* serialization

```gradle
    dependencies {
        classpath 'com.android.tools.build:gradle:3.6.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
    }
```

```gradle
apply plugin: 'kotlinx-serialization'

dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0"
}
```

---

[OpenWeather](https://openweathermap.org/) から天気の情報を取得してみたいと思います。
ログインして、Keyは取得済みとします。

### ViewModel

まず、ktorを初期化する。
OkHttp と KotlinxSerializer を使用します。

```kotlin
    private val httpClient = HttpClient(OkHttp) {
        install(JsonFeature) {
            serializer = KotlinxSerializer(
                Json(
                    JsonConfiguration.Stable.copy()
                )
            )
        }
    }
```

上記を使って、天気情報を取得する処理を実装します。
viewModelScope.launch が、coroutines の実装になります。
これだけで、非同期で通信する処理が実装出来ます。
また、取得できたら、LiveData を使って、UI側に通知します。

```kotlin
    val openWeatherMapLiveData = MutableLiveData<OpenWeatherMapJson>()

    fun getOpenWeatherMapJson() {
        viewModelScope.launch {
            try {
                val openWeatherMapJson = httpClient.post<OpenWeatherMapJson>("https://api.openweathermap.org/data/2.5/weather?q=yokohama&appid={KEY}") {
                    contentType(ContentType.Application.Json)
                }
                openWeatherMapLiveData.postValue(openWeatherMapJson)
            } catch (e:Exception) {
                Log.e("w", e.message)
            }
        }
    }
```

* OpenWeatherMapJson

Json部分の実装は、省略しますが、下記のような data class を用意します。

```kotlin
@Serializable
data class OpenWeatherMapJson(
    val coord: Coord,
    val weather: List<Weather>,
    val base: String,
    val main: Main,
    val visibility: Int,
    val wind: Wind,
    val clouds: Clouds,
    val dt: Int,
    val sys: Sys,
    val timezone: Int,
    val id: Int,
    val name: String,
    val cod: Int
)
```

### Activity

実際に取得する処理を実装します。
ViewModel を使って、非同期で通信し、レスポンスを受け取ったら、UIに表示する処理になります。

```kotlin

class MainActivity : AppCompatActivity() {

    private val viewModel by viewModels<MainViewModel>()

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

        fab.setOnClickListener { view ->
            viewModel.getOpenWeatherMapJson()
        }
        viewModel.openWeatherMapLiveData.observe(this, Observer {
            textView.text = it.name
        })
    }
}
```

### まとめ

retrofit でも同様なことが出来ます。
Android で、通信処理を実装する場合の選択肢として、ktor も使えますので是非使ってみてください。