Coroutines私的メモ3〜Coroutines Flow〜

[前回の続き](https://qiita.com/sudo5in5k/items/319a7c45923aebc04571)となります

# Coroutines Flowとは

`Cold`データーストリームの一種

## Cold？

RxJavaのObservableにもありますが、データストリームは`Cold`と`Hot`に大別できる

### Cold
* 1つの消費者(生産者の対義語)に対して購読関係を結ぶ (=個別に値を流していく)
* Subscribeするまで値を流さない
* 通知するデータのタイムラインが購読されるたびに生成
* 大抵のObservableはCold

<img width="600" alt="スクリーンショット 2019-12-29 14.07.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260353/9861b711-726a-2620-c5a1-51ae1c87dec8.png">

### Hot
* 複数の消費者(生産者の対義語)に対して購読関係を結ぶ
* Subscribeしなくても値が流れていく
* すでに作成した通知するデータストリームに、後から消費者が加わる
* RxJavaでいうところのConnectableFlowable/ConnectableObserver

<img width="600" alt="スクリーンショット 2019-12-29 14.07.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260353/cec57686-64ed-5e03-05a7-e0ac17b69a11.png">

※上記２つの図は[RxJavaリアクティブプログラミング](https://www.amazon.co.jp/RxJava%E3%83%AA%E3%82%A2%E3%82%AF%E3%83%86%E3%82%A3%E3%83%96%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-CodeZine-BOOKS-%E9%A0%88%E7%94%B0-%E6%99%BA%E4%B9%8B/dp/4798149519)から一部抜粋し、引用させていただきました

# 導入
```gradle
def coroutines_ver = "1.3.3"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_ver"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_ver"
```

# CoroutinesFlowの使い方の流れ

* Flow<T>でストリームを作成
* （任意)オペレータによる中間処理
* Flow<T>.collectで値を受け取っていく

## Flow<T>の作り方

例としてここでは1から10までのストリームをあげてみます

* `flowOf`

```kotlin
private fun getIntFlow1() = flowOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
```

* `asFlow()`

Iterable, Iterator, Sequenceに対して使うことができます

```kotlin
private fun getIntFlow2() = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).asFlow()
```

* `flow {}`

```kotlin
private fun getIntFlow3() = flow {
   repeat(10) {
       emit(it + 1)
   }
}
```

## オペレータによる中間処理
Rxにあったfilterやmapなど中間処理の関数をサポートしています
中間処理をする時点ではsuspendではないためこの点も便利ですね

```kotlin
val ints = getIntFlow1()
    .filter { it > 3 }
    .map { value ->
        "Value: $value"
    }
    .drop(1)
    .take(2)
```

上記では3以上のものをフィルタリングし、文字列に変換し、最初の1つを削除して、その中から最初の2つを選ぶということを行っています

Experimentalなものも未だ多い現状ですが、他にも様々な中間処理が使えますので[こちらのExtension Functions](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/)を御覧ください


## `Flow<T>.collect`
`Flow<T>`及び途中の中間処理まではsuspend関数ではないのでどこでも定義ができます
一方、受け取り側のFlow<T>.collectはsuspend関数のため、必ずコルーチンスコープ内で実行する必要があります
（逆にスコープの閉じ忘れがない事は利点になる)

```kotlin
val ints = getIntFlow1()
GlobalScope.launch(Dispatchers.Main) {
    ints.collect {
        delay(1000L)
        text.text = it
    }
}
```

※textはtextView

結果として1からはじまり、10まで1秒ごとにTextViewのtextに代入されViewに表示されていくことになります

### `Flow<T>.collectIndexed`
collectと同様に値も取得できますし、indexも取得できます

# さいごに
かんたんにCoroutines Flowについてとりあげました
次は今回は分量上避けていたFlowBuilderのうちの一つである`channelFlow<T>`に着目して取り上げてみたいと思います

# 参考にさせていただいたもの

* [kotlinx.coroutines.flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/)
* [RxJavaリアクティブプログラミング](https://www.amazon.co.jp/RxJava%E3%83%AA%E3%82%A2%E3%82%AF%E3%83%86%E3%82%A3%E3%83%96%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-CodeZine-BOOKS-%E9%A0%88%E7%94%B0-%E6%99%BA%E4%B9%8B/dp/4798149519)
* [５分でわかるKotlin Coroutines Flow](https://speakerdeck.com/sys1yagi/5fen-tewakarukotlin-coroutines-flow)