Flow 是什麼#
Flow 是 Kotlin Coroutine 用來處理「非同步資料流」的工具。它會按照發射(emit)的順序依次送出資料,最後正常結束或拋出例外。
官方文件描述:An asynchronous data stream that sequentially emits values and completes normally or with an exception.
把資料透過 Flow 發送出去之後,這些資料在被「接收」之前不會真的執行運算。我們甚至可以在接收前先用一些函式把資料轉成需要的形狀。
Flow 與 Channel 的差異#
兩者都能傳遞資料,但定位不同:
- Channel 一次取出一個值,需要呼叫多次
receive。 - Flow 取出的是整條資料流(Stream),用一次
collect就能處理整條流上的所有元素。
換個說法:
- 用 Channel 時,每筆資料對應一組
send/receive。 - 用 Flow 時,發射端用
emit,接收端用collect一次處理整串。
第一個 Flow 範例#
Kotlin 提供多種 flow 建構器(Flow Builder),這裡先用 flow { ... }:
fun flow1(): Flow<Int> = flow {
println("Flow started")
repeat(10) {
delay(100)
emit(it)
}
}幾個值得注意的點:
- 回傳
Flow<Int>的函式本身不需要是 suspend 函式。原因是 Flow 在被 collect 之前不會執行內部程式碼,真正會 suspend 的是接收端。 flow { ... }的 lambda 本身是 suspend 的(所以可以呼叫delay)。
builder 的簽名如下:
public fun <T> flow(@BuilderInference block: suspend FlowCollector<T>.() -> Unit): Flow<T> = SafeFlow(block)emit 其實是 FlowCollector 的成員函式:
public interface FlowCollector<in T> {
public suspend fun emit(value: T)
}接收 Flow 的資料#
Flow<T> 介面只有一個核心方法:
public interface Flow<out T> {
@InternalCoroutinesApi
public suspend fun collect(collector: FlowCollector<T>)
}也就是說,Flow 的設計可以總結為:
- 用
emit把值放進 stream。 - 用
collect把值取出來。
接收範例:
fun main() = runBlocking {
val flow = flow1()
flow.collect { value -> println(value) }
}執行結果:
Flow started
0
1
2
3
4
5
6
7
8
9小結#
- Flow 是非同步處理資料流的方式,發射用
emit、接收用collect。 - 建立 flow 的函式不需要是 suspend,因為內部的程式碼要等到
collect時才會執行。 - 跟 Channel 比起來,Flow 處理的是整串資料,搭配後續介紹的中間運算子使用會非常順手。
- 下一章我們會再多看一個 Flow 的重要特性:它是 Cold Stream。
原文出處#
- 原書/iThome:https://ithelp.ithome.com.tw/articles/10269815