Skip to content

Flow 基础与冷流原理

源:异步流官方指南

Flow 是 Kotlin 协程生态中处理异步数据流的标准组件。它结合了 Sequence 的惰性求值和 Coroutine 的挂起特性。

冷流特性 (Cold Stream)

核心定义:Flow 是“冷”的——如果不收集,它就不运行。 这与热流(如 StateFlow, Channel)形成鲜明对比。

mermaid
graph LR
    Builder[flow { ... }] -- 1. 定义逻辑 (不执行) --> Instance[Flow 实例]
    Instance -- 2. 调用 collect() --> Execution[开始执行发射逻辑]
kotlin
val coldFlow = flow {
    println("Starting flow...")
    emit(1)
}

// 此时控制台没有任何输出
// 只有调用 collect 才会触发
coldFlow.collect { ... }

常用构建器

构建器描述示例
flow { ... }最通用,支持挂起函数flow { delay(100); emit(1) }
flowOf(...)发射固定的一组值flowOf("A", "B")
.asFlow()将集合、区间转换流listOf(1, 2).asFlow()

上下文保存 (Context Preservation)

这是 Flow 最严格的契约。 Flow 的发射逻辑(emit)必须在收集器(collect)所在的上下文中执行。

严禁内部切换

不要在 flow { ... } 内部使用 withContext 切换线程。这会破坏流的上下文一致性,导致运行时抛出异常。

kotlin
// ❌ 错误做法
flow {
    withContext(Dispatchers.IO) { emit(1) } // Crash!
}

// ✅ 正确做法:使用 flowOn
flow {
    emit(1)
}.flowOn(Dispatchers.IO) // 专门用于上游线程切换的操作符

性能优化:emitAll

如果你需要发射另一个 Flow 的所有数据,请使用 emitAll 而不是 flow.collect { emit(it) }emitAll 内部没有任何对象分配开销,直接将当前的 FlowCollector 委托给目标 Flow。

kotlin
// ❌ 低效
flow {
    anotherFlow.collect { value -> emit(value) }
}

// ✅ 高效
flow {
    emitAll(anotherFlow)
}