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)
}