渐进式编程课
KMP 目录
第 6 课2026.07.22

一次网络请求通常返回一个结果,适合使用 suspend;行情、数据库列表、登录状态等数据会持续变化,更适合使用 Flow。KMP 可以在共享层定义数据流,再由 Android 和 iOS 观察同一套业务数据。

第 6 课:用 Flow 表达共享数据流

  • 日期:2026-07-22
  • 课程序号:06
  • 知识点:在 commonMain 中使用 Flow 连续发送数据

用途

一次网络请求通常返回一个结果,适合使用 suspend;行情、数据库列表、登录状态等数据会持续变化,更适合使用 Flow。KMP 可以在共享层定义数据流,再由 Android 和 iOS 观察同一套业务数据。

核心概念

  • suspend fun load(): T:完成一次异步任务,返回一个结果。
  • fun observe(): Flow<T>:随着时间推移,可以连续发送多个结果。
  • emit(value):向数据流发送一个值。
  • collect { value -> ... }:订阅并处理每个值,必须在协程中调用。
  • 普通 flow {} 是冷流:没有收集者时不会执行,每个收集者都会独立启动一次。

示例代码

本课沿用上一课已经加入 commonMain 的 kotlinx-coroutines-core 依赖。

commonMain/PriceRepository.kt:

kotlin
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

class PriceRepository {
    fun observePrices(): Flow<Double> = flow {
        val prices = listOf(10.0, 10.5, 10.2)

        for (price in prices) {
            emit(price)
            delay(500)
        }
    }
}

调用方需要在自己的协程作用域中收集:

kotlin
lifecycleScope.launch {
    PriceRepository().observePrices().collect { price ->
        println("最新价格:$price")
    }
}

输出顺序为:

text
最新价格:10.0
最新价格:10.5
最新价格:10.2

收集协程被取消时,delay 和数据流也会一起取消,因此平台调用层仍然负责把收集过程绑定到正确的生命周期。

5 分钟练习

写一个 observeLoginState(): Flow<Boolean>,依次发出 false 和 true,两次发送之间等待 300 毫秒。

参考答案

kotlin
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

fun observeLoginState(): Flow<Boolean> = flow {
    emit(false)
    delay(300)
    emit(true)
}

调用方可以用 collect { isLoggedIn -> ... } 接收每次状态变化。这里的数据源决定真实状态,UI 只负责渲染收集到的结果。

与上一课的联系

上一课用 suspend 表示一次异步操作;本课把协程扩展为连续数据流。记住选择标准:只需要一个结果时用 suspend,需要观察多个变化时用 Flow。