Slide 1

Slide 1 text

Coroutines Flow 入門 Kenji Abe

Slide 2

Slide 2 text

Coroutines Flow とは •雑に言うと、RxJavaみたいなやつ •Cold Stream ‣ 受信しはじめてから動き始める ‣ Hot Stream は Channel

Slide 3

Slide 3 text

Coroutines Flow とは • ↓ の資料が分かりやすいので、そっちを見て ‣ https://speakerdeck.com/sys1yagi/5fen- tewakarukotlin-coroutines-flow •この資料では色々な使い方を紹介します

Slide 4

Slide 4 text

基本的なやつ fun main() = runBlocking { val flow = flow { repeat(3) { emit(it) } } flow.collect { println(it) } }

Slide 5

Slide 5 text

基本的なやつ fun main() = runBlocking { val flow = flow { repeat(3) { emit(it) } } flow.collect { println(it) } } Flow builder

Slide 6

Slide 6 text

基本的なやつ fun main() = runBlocking { val flow = flow { repeat(3) { emit(it) } } flow.collect { println(it) } } 値を送出

Slide 7

Slide 7 text

基本的なやつ fun main() = runBlocking { val flow = flow { repeat(3) { emit(it) } } flow.collect { println(it) } } 値を受信

Slide 8

Slide 8 text

Flow builders •Flow { } •flowOf(...) ‣ flowOf(1, 2, 3) •(() -> T).asFlow() ‣ ({ 1 }).asFlow()

Slide 9

Slide 9 text

Intermediate operators •map •filter •take •zip

Slide 10

Slide 10 text

Flow operators fun main() = runBlocking { val flow = flowOf(1, 2, 3, 4, 5) flow.map { it * 2 }.collect { println(it) } } 値を2倍

Slide 11

Slide 11 text

Flow operators fun main() = runBlocking { val flow = flowOf(1, 2, 3, 4, 5) flow.filter { it % 2 == 0 }.collect { println(it) } } 偶数のみ

Slide 12

Slide 12 text

Terminal operators •collect •single •reduce •toList

Slide 13

Slide 13 text

Terminal operators fun main() = runBlocking { val flow = flowOf(1, 2, 3, 4, 5) val value = flow .filter { it == 5 } .single() println(value) // 5 } 複数の値の場合は例外になる

Slide 14

Slide 14 text

Terminal operators fun main() = runBlocking { val flow = flowOf(1, 2, 3, 4, 5) val value = flow .reduce { accumulator, value -> accumulator + value } // 1 + 2 + 3 + 4 + 5 println(value) // 15 }

Slide 15

Slide 15 text

Terminal operators fun main() = runBlocking { val flow = flowOf(1, 2, 3, 4, 5) val value = flow .toList() println(value) // [1, 2, 3, 4, 5] }

Slide 16

Slide 16 text

Change context •flowOn ‣ 上流のContextを変更する ‣ Flowにおいて唯一Contextを切り替える方法 •emitするときにContextが異なると例外

Slide 17

Slide 17 text

Change context fun main() = runBlocking { val flow = flowOf(1, 2, 3, 4, 5) flow .map { println("map: ${Thread.currentThread().name}") it + 1 } .flowOn(Dispatchers.IO) .collect { println("collect: ${Thread.currentThread().name}") } } worker main

Slide 18

Slide 18 text

Change context fun main() = runBlocking { val flow = flowOf(1, 2, 3, 4, 5) flow .map { } .flowOn(Dispatchers.IO) .filter { } .flowOn(Dispatchers.Default) .map { } .flowOn(Dispatchers.IO) .collect { } }

Slide 19

Slide 19 text

Change context fun main() = runBlocking { val flow = flowOf(1, 2, 3, 4, 5) flow .map { } .flowOn(Dispatchers.IO) .flowOn(Dispatchers.Default) .collect { } } 最初のやつが優先

Slide 20

Slide 20 text

Change context fun main() = runBlocking { val flow = flow { emit(1) launch { emit(2) } } flow.collect { } } emit時にContextが違うので 例外になる

Slide 21

Slide 21 text

Exception •catchを使って捕捉できる •上流のストリームの例外のみ捕捉 •onCompletionでfinallyみたいなこともできる

Slide 22

Slide 22 text

Exception fun main() = runBlocking { flow { } .map { } .catch { } .map { } .catch { } .collect { } } ① ② ③ ③の例外はここで捕捉 ①と②の例外はここで捕捉 それ以降は実行されない

Slide 23

Slide 23 text

Exception fun main() = runBlocking { flow { emit(1) }.catch { emit(-1) }.collect { println(it) } } 例外発生時に別の値を送出

Slide 24

Slide 24 text

Exception fun main() = runBlocking { flow { } .map { } .onCompletion { } .map { } .onCompletion { } .collect { } } finallyみたいなやつ

Slide 25

Slide 25 text

おわり