３分で理解する coroutine + retrofit2

## なぜcorutineを使用するのか？
非同期処理のコールバック地獄を防ぐ為です。
corutineを使用することにより、非同期処理をより高速に、少ない行数で書くことができます。
もちろんcorutineを使用しなくても非同期処理をかけますが、corutineを使った方が遥かに簡単に実装できます。

この記事では３分でcorutine + retorofit2 を理解することを目指します。

## セットアップ
Android StudieでEmptyActivityを選択し、kotolinでHelloWorldというアプリを作成してください。
<img width="903" alt="スクリーンショット 2020-06-09 22.04.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183835/cc5abe18-beae-977b-e651-ebb566a817b3.png">


4つのライブラリを追加

retrofit = http通信ライブラリ 2020年のhttpリクエストのデファクトスタンダード
converter-gson = retorofitで使用する　jsonのパーサー
coroutines-core = coroutineのコア。　coroutineは、kotlinとは別々に提供される。
lifecycle-runtime = 後述するlifecycleScopeを使用する為のもの。　kotlin公式

```gradle
// 以下二行は、retrofit
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
// 以下二行はcoroutine
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'
```

## http通信を許可する
Androidでは通信を行うにはAndroidManifestに以下の一行を加え、通信を許可する必要がある。

```
 <uses-permission android:name="android.permission.INTERNET"/>
```
をAndroidiManifestに加えて、http通信を許可する。


```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.helloworld">

+    <uses-permission android:name="android.permission.INTERNET"/>


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
```

## 実装
これから出てくるコードは全てMainActivityの中に記述する。厳密には正しくないが、シンプルさの為にいらないコードは削除している。

初期MainActivityは以下

```kotlin
package com.example.helloworld

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {

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

モデルを作成する。
今回取得するjsonは以下

```
{
  "name": "kabaya",
  "job": "engineer"
}
```
そこでこのjsonに対応するモデルを作成し、retorofitがAPIレスポンスの結果を代入する。

```kotlin
// MainActivity.kt
data class ApiResponse(
        val name: String,
        val job: String
)
```

## retrofitのセットアップ
retrofit自体は、jsonのパースをする機能はないため、ここでは有名なGsonというjsonをパースするライブラリを利用する。
GsonConverterFactory.create()が、retrofit用のGsonだ。
よくあるBuilderパターンでビルドした後createメソッドに後述するretorofitのinterfaceを渡す。

```kotlin
val api = Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .baseUrl("https://gist.githubusercontent.com/t-kabaya/")
        .build().create(ApiInterface::class.java)
```

retorofitのセットアップは一行で完成した。

## interfaceを定義する
interfaceを定義する。
このinterface内に関数とその戻り値を定義しておく。

```kotlin
interface ApiInterface {
    @GET("0616752fd86043f79f8a61e93f25d022/raw/a129469a6895c7e95fa0511efcf4c4f012ef0e0e/helloRetrofit")
    suspend fun getUser(): ApiResponse
}
```

## coroutineを作成する。
onCreateの中に以下の２行を書くことで、非同期処理を行うためのcoroutineを作成出来る。
lifecycleScopeは、Activity, Fragmentなどlifecycleがあるクラスで使用可能なcorutineのためのスコープだ。
lifecycleが破棄される時に、lifecycleScopeも同時に破棄される。
他にもいろいろな種類のScopeがあるので、適切に選択する必要がある。
今回はonCreate内部でcoroutineを作成するのでlifecycleScopeを使用する。

```kotlin

lifecycleScope.launch {
}
```

## suspend関数
suspend関数は、coroutineまたは他のsuspend関数内でのみ使用可能な関数で、suspend関数内部で発生する非同期な処理が終了するのを待ってから、次の処理へ移る。
つまり、suspend関数内部でhttpリクエストを行えば、リクエストの結果が帰ってくるまで待ち、その後処理を進めることが可能だ。

先ほどインターフェースで定義したgetUserをここで使用する。

```kotlin
suspend fun getRequest(): ApiResponse? {
    try {
        val response: ApiResponse = api.getUser()
        return response
    } catch (e: Exception) {
        return null
    }
}
```

## corutineの中でsuspend関数を実行
suspend関数は、corutineの中か、他のsuspend関数の中でしか使用できないことを思い出してほしい。
先ほど作成したcorutineの中でgetRequsetを呼ぶ。

非同期処理を、同期的に書くことに成功した。

```kotlin

lifecycleScope.launch {
    val response = getRequest()
    Log.d("response ", response.toString())
}
```

## 完成したコード

```kotlin
package com.example.helloworld

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET

val api = Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .baseUrl("https://gist.githubusercontent.com/t-kabaya/")
        .build().create(ApiInterface::class.java)

data class ApiResponse(
        val name: String,
        val job: String
)

interface ApiInterface {
    @GET("0616752fd86043f79f8a61e93f25d022/raw/a129469a6895c7e95fa0511efcf4c4f012ef0e0e/helloRetrofit")
    suspend fun getUser(): ApiResponse
}

suspend fun getRequest(): ApiResponse? {
    try {
        val response: ApiResponse = api.getUser()
        return response
    } catch (e: Exception) {
        return null
    }
}

class MainActivity : AppCompatActivity() {

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

        lifecycleScope.launch {
            val response = getRequest()
            Log.d("response ", response.toString()) // ApiResponse(name=kabaya, job=engineer)
        }
    }
}
```

## お願い
いいねください。