什麼是冷資料流#

Flow 的一個重要特性是它屬於 冷資料流(Cold Stream):在沒有人呼叫 collect 之前,flow 內部的程式碼不會被執行。

換句話說:

  • 建立 Flow 只是「定義」資料如何被產生。
  • 呼叫 collect 才會真正啟動產生資料的流程。
  • 每呼叫一次 collect,flow 內的程式碼就會重新執行一次。

這個性質與「熱資料流」(Hot Stream)對比:熱資料流會主動發送資料,不論有沒有訂閱者;冷資料流則只在被訂閱時才執行。

Cold Stream 範例#

延續前一篇的 flow1

fun flow1(): Flow<Int> = flow {
    println("Flow started")
    repeat(10) {
        delay(100)
        emit(it)
    }
}

如果 collect 兩次:

fun main() = runBlocking {
    val flow = flow1()
    flow.collect { value -> println(value) }
    flow.collect { value -> println(value) }
}

執行結果:

Flow started
0
1
2
3
4
5
6
7
8
9
Flow started
0
1
2
3
4
5
6
7
8
9

可以看到 Flow started 被印了兩次,0 ~ 9 也跑了兩遍。這證明:

  • 同一個 Flow 物件可以被多次 collect。
  • 每一次 collect,都會從頭跑一次 flow 內的程式碼。

為什麼這個性質重要#

冷資料流帶來幾個好處:

  • 「定義」與「執行」解耦:可以先把資料來源寫好放著,要用的時候才觸發。
  • 多次訂閱可以拿到一致的資料序列,不用擔心「之前的資料已經跑掉了」。
  • 中間運算子(map、filter 等)可以放心地疊在冷流之上,因為整條鏈路會在 collect 時統一觸發。

反過來說,如果需要的是「不論誰訂閱、資料都持續流動」的場景,例如點擊事件、感測器資料,就需要 SharedFlow / StateFlow 這類「熱資料流」工具。

小結#

  • Flow 是冷資料流:沒有 collect,內部就不執行。
  • 每次 collect 都會重新執行 flow 內的程式碼,得到全新的一條流。
  • 建立 Flow 的函式不需要是 suspend,因為它只是宣告。
  • 真正會 suspend 的是 collect 端。

原文出處#

  • 原書/iThome:https://ithelp.ithome.com.tw/articles/10269815