よく分かってないKotlin Coroutine

## はじめに
Android開発でKotlin Coroutineを使用しているのですが、なんとなく使用していて「あ〜非同期処理を簡単に書けて便利だな〜」くらいの理解しかなかったため、今回はCoroutineの理解と備忘録として記事を作成したいと思います。

## Coroutineとは
Coroutineとは軽量のスレッドのようなもので、スレッドのように他の処理をブロックすることなく並列に行うことができます。
スレッドよりは軽量で10000個のCoroutineを同時に走らせることもできるみたい。

なにより一番の魅力は**非同期処理を同期的に書くことができます。**
また、非同期処理実行途中であっても **中断/再開** することが可能です。

## Coroutine登場とそれ以前
以下の典型的な非同期処理をCoroutineを使用しない/使用するパターンで比べてみる
1.サーバーから情報を取得する(ここではただの文字列)
2. 取得した情報をViewに反映する

### Coroutineを使用しない非同期処理
Coroutineが登場する前のAndroidアプリでの非同期処理は主にコールバックを使用していました。

``` java
public static void main(String[] args) {
    object : AsyncTask<Void, Int, String?>() {
        override fun doInBackground(vararg params: Void?): String? {
            String result = Repository.getString()
            return result
        }
    
        override fun onPostExecute(result: String?) {
            binding.name.setText(result)
        }
    }.execute(null)
}
```

### Coroutineを使用した非同期処理
```Kotlin
fun main(args: Array<String>) {
    launch(Dispachers.IO) {
        // Backgroundスレッド
        val result = Repository.getString()
        withContext(Dispatchers.Main) {
            // Mainスレッド
            binding.name.text = result                
        }
    }
}
```
このようにCoroutineを使用することで簡単にスレッドを切り替えて処理をすることができます。

## Coroutineの使い方
Coroutineの作成には **CoroutineBuilderを使用します**

作成した**CoroutineBuilder** の種類によって挙動が異なります。

### runBlocking
**runBlocking**　は現在のスレッドをブロックします。
UIスレッドで扱う場合は注意が必要です。

```Kotlin
    fun sample() {
        println(1)
        runBlocking {
            println(2)
        }
        println(3)
    }

// 結果
// 1
// 2
// 3  
```

### launch
```kotlin
    fun sample() {
        println(1)
        launch {
            println(2)
        }
        println(3)
    }

// 結果
// 1
// 3
```
**launch** スコープで囲って上げることでCoroutineを開始できます。
現在のスレッドをブロックしないので **launch**内の処理が終了する前にプログラムが終了しています。

また、**join()** を使用することで開始したCoroutine内の処理が終了するまで待機することができます。
```Kotlin
    fun sample() {
        runBlocking {
            println(1)
            launch {
                println(2)
            }.join()
            println(3)
        }
    }

// 結果
// 1
// 2
// 3
```

### async
**launch** 同様現在のスレッドをブロックしないので **async** 内の処理が終了する前にプログラムが終了します。

```Kotlin
    fun sample() {
        println(1)
        async {
            println(2)
        }
        println(3)
    }

// 結果
// 1
// 3
```

**await()** を使用することで開始したCoroutine内の処理が終了するまで待機することができます。

```Kotlin
    fun sample() {
        runBlocking {
            println(1)
            async {
                println(2)
            }.await()
            println(3)
        }
    }

// 結果
// 1
// 2
// 3
```

## Coroutineを扱うために必要な概念

### CoroutineContext
Coroutineを実行するための情報がすべて入っている。

### job 
**CoroutineBuilder** によって作成されたCoroutine。

### CoroutineScope
Coroutineを使用できる範囲を設定する。CoroutineContextを持っている

### Dispacher
Coroutineが実行されるスレッドを決定するもの。
4つのDispacherが用意されています。
- **Dispatchers.Main**
    Mainスレッドを指定。 
- **Dispatchers.Default**
    バックグラウンドスレッドを使用。
    CPUに負荷のかかる処理をする際にしようする。(例:ローカルでのListの並び替え等)
- **Dispatchers.IO**
    バックグラウンドスレッドを使用。
    IO(Input/Output)操作を処理する際に使用する。(例:DB通信/Http通信)
- **Dispatchers.Unconfined**
    特定のスレッドに限定されない。公式によると普通は使用しないらしい。

## Suspend関数
CoroutineにはCoroutine内で処理を中断できるSuspendFunctionなるものが用意されています。

suspend修飾子を付けることで宣言可能です。
**suspend関数はCoroutineScope内からでないと呼び出すことができません。**
**また、suspend関数の処理が終了するまで呼び出し元のCoroutineScope内の処理が止まります。** ←これめっちゃ便利
```Kotlin
suspend fun sample(){
    // 呼び出し元のCoroutineスコープ内で処理を止めたい処理
}
```

```Kotlin
    fun sample() {
        runBlocking {
            println(1)
            delay(1000)
            println(2)
        }
    }

// 結果
// 1
// 1秒中断
// 2
```

**delay()** はsuspend関数です
```Kotlin
public suspend fun delay(timeMillis: Long) {
    if (timeMillis <= 0) return // don't delay
    return suspendCancellableCoroutine sc@ { cont: CancellableContinuation<Unit> ->
        cont.context.delay.scheduleResumeAfterDelay(timeMillis, cont)
    }
}
```

## Coroutine内での実行スレッド管理
冒頭の[Coroutine登場とそれ以前](#coroutine登場とそれ以前) でも少し触れましたが、Coroutineでは実行するスレッドを簡単に変更/指定することができます。

### スレッドを指定してCoroutineを開始する
スレッドを指定してCoroutineを起動する場合
```Kotlin 
launch(Dispatchers.Main) {
    // このCoroutineScope内はMainスレッドで実行される
}
```

### Coroutine内で実行スレッドを変更する
Coroutine内では**withContext(Dispatchers.(実行モード))** で実行スレッドを簡単に変更することができます。
```Kotlin
launch {
    // このCoroutineScope内はMainスレッドで実行される
    withContext(Dispatchers.IO) {
        // このCoroutineScope内はBackgroundスレッド(IO)で実行される
    }
}
```
## さいごに
今回はKotlinCoroutineをおさらいしてみました。
僕はエンジニアになった時には既にKotlinCoroutineがあったので登場前の大変さは実体験としては分かっていませんが、Coroutineのおかげで簡単に非同期処理が書けるんだなと改めて感じました。

ではまたっ！