一、简单用法
1. Flow 概述
Flow 是 Kotlin 协程库中用于处理异步数据流的 API,类似于 RxJava 的 Observable,但更轻量且与协程深度集成。
主要特点:
- 冷流(Cold Stream) :消费者触发时才执行
- 基于协程:天然支持挂起函数
- 响应式编程:支持函数式操作符
- 结构化并发:自动取消和资源清理
2. Flow 的创建
// 1. flow {} 构建器
val flow1 = flow {
for (i in 1..3) {
delay(100) // 挂起函数
emit(i) // 发射值
}
}
// 2. asFlow() 扩展函数
val flow2 = listOf(1, 2, 3).asFlow()
val flow3 = (1..3).asFlow()
// 3. flowOf()
val flow4 = flowOf(1, 2, 3)
// 4. channelFlow - 支持复杂异步场景
val flow5 = channelFlow {
send(1)
withContext(Dispatchers.IO) {
send(2)
}
}
3. Flow 操作符
3.1 中间操作符(Intermediate Operators)
// 转换操作
flow.map { it * 2 } // 映射
flow.filter { it > 5 } // 过滤
flow.transform { value ->
emit("Value: $value")
emit(value * 10)
}
// 限长操作
flow.take(2) // 取前两个
flow.takeWhile { it < 3 } // 条件取
// 组合操作
val flowA = flowOf(1, 2, 3)
val flowB = flowOf("A", "B", "C")
flowA.zip(flowB) { a, b -> "$a -> $b" } // 压缩
flowA.combine(flowB) { a, b -> "$a - $b" } // 组合(最新值)
// 展平操作
flow.flatMapConcat { value -> // 顺序连接
flowOf(value, value * 2)
}
flow.flatMapMerge { value -> // 并发合并
flow {
delay(100)
emit(value)
}
}
flow.flatMapLatest { value -> // 最新值
flow {
delay(100)
emit(value)
}
}
3.2 终端操作符(Terminal Operators)
// 收集值
flow.collect { value ->
println(value)
}
// 转换为集合
val list = flow.toList()
val set = flow.toSet()
// 聚合操作
val sum = flow.reduce { acc, value -> acc + value }
val sum2 = flow.fold(0) { acc, value -> acc + value }
// 获取单个值
val first = flow.first()
val firstOrNull = flow.firstOrNull()
val single = flow.single() // 确保只有一个值
// 计数
val count = flow.count()
4. 异常处理
// catch 操作符
flow.catch { cause ->
println("Caught exception: $cause")
emit(-1) // 发射备用值
}.collect { value ->
println(value)
}
// 声明式异常处理
flow.onCompletion { cause ->
cause?.let { println("Flow completed exceptionally: $it") }
?: println("Flow completed successfully")
}
// 示例:多层捕获
flow
.map { it * 2 }
.catch { emit(-1) } // 只捕获上游异常
.collect { value ->
try {
println(value)
} catch (e: Exception) {
// 处理收集端异常
}
}
5. 上下文和线程切换
// flowOn - 指定上游操作的上下文
flow
.map { it * 2 } // 在 IO 线程执行
.flowOn(Dispatchers.IO)
.collect { value -> // 在调用者上下文执行
println(value)
}
// 错误示例:不要在 flow 构建器中切换上下文
val wrongFlow = flow {
withContext(Dispatchers.IO) { // ❌ 错误!
emit(1)
}
}
// 正确做法:使用 channelFlow 或 flowOn
val correctFlow = flow {
emit(1)
}.flowOn(Dispatchers.IO)
6. 背压(Backpressure)处理
// 缓冲
flow.buffer() // 默认缓冲
flow.buffer(10) // 指定缓冲大小
// 合并(跳过中间值)
flow.conflate() // 只处理最新值
// 收集最新值
flow.collectLatest { value ->
// 如果新值到达,取消当前处理
delay(300) // 模拟耗时操作
println(value)
}
7. 热流(Hot Flow)
7.1 SharedFlow
// 创建 SharedFlow
val sharedFlow = MutableSharedFlow<Int>(
replay = 2, // 新订阅者接收的历史值数量
extraBufferCapacity = 10 // 额外缓冲
)
// 发射值
viewModelScope.launch {
sharedFlow.emit(1)
}
// 收集值
sharedFlow.collect { value ->
println("Collector 1: $value")
}
// shareIn - 将冷流转为热流
val coldFlow = flow {
repeat(10) {
emit(it)
delay(100)
}
}
val hotFlow = coldFlow.shareIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(), // 订阅时开始
replay = 1
)
// started 参数选项:
// SharingStarted.Eagerly - 立即开始
// SharingStarted.Lazily - 第一个订阅者出现时开始
// SharingStarted.WhileSubscribed() - 有订阅者时开始
7.2 StateFlow
// 创建 StateFlow
val stateFlow = MutableStateFlow(0) // 需要初始值
// 更新值(自动去重)
stateFlow.value = 1
stateFlow.tryEmit(2)
// 收集值(自动接收最新值和后续更新)
stateFlow.collect { value ->
println("Current state: $value")
}
// stateIn - 将 Flow 转换为 StateFlow
val state = flow {
emit(1)
delay(1000)
emit(2)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000), // 5秒后无订阅者停止
initialValue = 0
)
8. Flow 生命周期
flow
.onStart {
println("Flow started")
}
.onEach { value ->
println("Emitted: $value")
}
.onCompletion { cause ->
cause?.let { println("Completed with exception: $it") }
?: println("Completed successfully")
}
.catch { cause ->
println("Caught: $cause")
}
.collect()
9. 实际应用示例
9.1 网络请求重试
fun fetchDataWithRetry(): Flow<Result> = flow {
var retryCount = 0
while (true) {
try {
val result = api.fetchData()
emit(Result.Success(result))
break
} catch (e: Exception) {
retryCount++
if (retryCount > MAX_RETRIES) {
emit(Result.Error(e))
break
}
delay(retryCount * 1000L) // 指数退避
}
}
}
9.2 搜索防抖
fun search(queryFlow: Flow<String>): Flow<List<Result>> = queryFlow
.debounce(300) // 防抖 300ms
.distinctUntilChanged() // 去重
.filter { it.length >= 2 } // 最小长度
.flatMapLatest { query -> // 取消前一个搜索
if (query.isEmpty()) {
flowOf(emptyList())
} else {
flow {
emit(emptyList<Result>()) // 显示加载状态
val results = api.search(query)
emit(results)
}.catch { emit(emptyList()) } // 错误时返回空
}
}
.flowOn(Dispatchers.IO)
9.3 组合多个数据源
fun observeUserData(userId: String): Flow<UserData> {
val localFlow = database.observeUser(userId)
val remoteFlow = api.getUserStream(userId)
return merge(localFlow, remoteFlow)
.distinctUntilChanged()
.onEach { user ->
database.saveUser(user)
}
}
10. 性能优化技巧
// 1. 避免不必要的中间操作
flow
.filter { it > 0 } // 尽早过滤减少后续操作
.map { it * 2 }
// 2. 合理使用 buffer
flow
.buffer() // 生产和消费并发执行
.collect { value ->
delay(100) // 模拟耗时消费
println(value)
}
// 3. 使用 shareIn/stateIn 避免重复计算
val sharedData = expensiveFlow
.shareIn(scope, SharingStarted.Lazily)
// 4. 适时取消不必要的流
scope.launch {
withTimeout(5000) {
flow.collect { value ->
if (value == TARGET) {
return@withTimeout // 找到目标后取消
}
}
}
}
11. 常见陷阱和最佳实践
11.1 陷阱
- 在 flow 构建器中使用 withContext ❌
// 错误
flow { withContext(Dispatchers.IO) { emit(1) } }
// 正确
flow { emit(1) }.flowOn(Dispatchers.IO)
- 捕获异常位置不当
// catch 只能捕获上游异常
flow.catch { /* 捕获上游异常 */ }
.collect {
try { /* 处理收集端逻辑 */ }
catch(e: Exception) { /* 捕获收集端异常 */ }
}
- 忘记处理取消
flow {
emit(1)
delay(1000)
emit(2) // 如果 flow 被取消,这里不会执行
}.cancellable() // 让 flow 可响应取消
11.2 最佳实践
- 使用
flowOn进行线程切换 - 合理使用
catch进行异常处理 - 使用
shareIn/stateIn共享热流 - 为耗时操作添加缓冲
- 及时取消不再需要的流
Flow 是 Kotlin 异步编程的强大工具,通过合理使用各种操作符和模式,可以构建出高效、可维护的异步数据流。
二、深入理解
1. Flow 的整体架构
1.1 Flow 接口体系
// Flow 核心接口
public interface Flow<out T> {
public suspend fun collect(collector: FlowCollector<T>)
}
public interface FlowCollector<in T> {
public suspend fun emit(value: T)
}
// Flow 构建器返回的 SafeFlow 实现
private class SafeFlow<T>(
private val block: suspend FlowCollector<T>.() -> Unit
) : Flow<T> {
override suspend fun collect(collector: FlowCollector<T>) {
val safeCollector = SafeCollector(collector, coroutineContext)
try {
block(safeCollector)
} finally {
safeCollector.releaseIntercepted()
}
}
}
1.2 Flow 执行模型
Flow 执行模型:
生产者 (Producer) → 中间操作符 (Intermediate Operators) → 消费者 (Consumer)
实际调用链:
collect() → 中间操作符1.collect() → 中间操作符2.collect() → ... → 源Flow.collect()
数据流向:
源Flow.emit() → 中间操作符1.emit() → 中间操作符2.emit() → ... → 消费者处理
2. Flow 构建原理
2.1 flow {} 构建器实现
// flow {} 构建器的实现
public fun <T> flow(
block: suspend FlowCollector<T>.() -> Unit
): Flow<T> = SafeFlow(block)
// 示例代码的字节码近似实现
flow {
emit(1)
emit(2)
}
// 实际被编译为(简化表示):
object : Flow<Int> {
override suspend fun collect(collector: FlowCollector<Int>) {
// 构建器lambda被编译为一个内部类
collector.emit(1)
collector.emit(2)
}
}
2.2 SafeCollector 的关键作用
internal actual class SafeCollector<T> actual constructor(
private val collector: FlowCollector<T>,
private val collectContext: CoroutineContext
) : FlowCollector<T>, Continuation<Unit> {
// 保存当前协程上下文
private val lastEmissionContext: CoroutineContext? = null
// emit 方法的线程安全实现
override suspend fun emit(value: T) {
// 1. 检查协程上下文是否发生变化(防止错误的线程切换)
checkContext(currentContext)
// 2. 保存发射上下文
lastEmissionContext = currentContext
// 3. 实际发射值
return suspendCoroutineUninterceptedOrReturn { cont ->
// 使用 Continuation 进行挂起恢复
with(collector) {
emit(value)
}
// 如果挂起,返回 COROUTINE_SUSPENDED
// 否则返回 Unit
}
}
private fun checkContext(currentContext: CoroutineContext) {
// 确保 emit 调用在正确的上下文中
if (lastEmissionContext != null && lastEmissionContext != currentContext) {
error("Flow invariant is violated")
}
}
}
3. 操作符实现原理
3.1 中间操作符 - Map 实现
// map 操作符的实现
public inline fun <T, R> Flow<T>.map(
crossinline transform: suspend (value: T) -> R
): Flow<R> = flow { // 创建一个新的 Flow
collect { value -> // 收集上游 Flow 的值
// 对每个值应用转换函数
val transformed = transform(value)
// 向下游发射转换后的值
emit(transformed)
}
}
// 使用示例对应的调用链
flowOf(1, 2, 3)
.map { it * 2 }
.collect { println(it) }
// 调用链展开:
// 1. 调用 collect() 终端操作符
// 2. 触发 map 创建的 Flow 的 collect 方法
// 3. map Flow 的 collect 方法调用上游 flowOf 的 collect
// 4. flowOf 发射值 1 → map 接收并转换 → 向下游发射 2 → collect 打印 2
// 5. 重复步骤4
3.2 终端操作符 - Collect 实现
// collect 的实际工作流程
public suspend inline fun <T> Flow<T>.collect(
crossinline action: suspend (value: T) -> Unit
): Unit = collect(object : FlowCollector<T> {
override suspend fun emit(value: T) = action(value)
})
// 更底层的实现
public suspend fun <T> Flow<T>.collect(collector: FlowCollector<T>) {
// 调用 Flow 接口的 collect 方法
return collect(collector)
}
4. 异常处理原理
4.1 catch 操作符实现
public fun <T> Flow<T>.catch(
action: suspend FlowCollector<T>.(cause: Throwable) -> Unit
): Flow<T> = flow {
// 异常处理逻辑
val exception = catchImpl(this)
if (exception != null) action(exception)
}
// 实际的异常捕获实现
internal suspend fun <T> Flow<T>.catchImpl(
collector: FlowCollector<T>
): Throwable? {
return try {
collect(collector)
null // 正常完成,返回 null
} catch (e: Throwable) {
// 只捕获上游异常,不捕获下游异常
if (e is DownstreamExceptionElement) {
throw e // 下游异常重新抛出
}
e // 返回上游异常
}
}
5. 上下文切换原理
5.1 flowOn 实现机制
public fun <T> Flow<T>.flowOn(context: CoroutineContext): Flow<T> {
// 创建 ChannelFlow 来处理上下文切换
return ChannelFlowOperatorImpl(this, context = context)
}
// ChannelFlowOperatorImpl 关键部分
internal class ChannelFlowOperatorImpl<T>(
private val flow: Flow<T>,
context: CoroutineContext
) : ChannelFlow<T>(context) {
override suspend fun collectTo(scope: ProducerScope<T>) {
// 在新的协程上下文中收集上游 Flow
coroutineScope {
// 使用新的上下文
withContext(context) {
flow.collect { value ->
// 将值发送到 channel
scope.send(value)
}
}
}
}
override suspend fun collect(collector: FlowCollector<T>) {
// 创建 channel 来处理背压
val channel = produceIn(this)
// 从 channel 中消费并发送给收集器
channel.consumeEach { value ->
collector.emit(value)
}
}
}
5.2 为什么不能在 flow {} 中直接切换上下文
// 错误的做法
flow {
withContext(Dispatchers.IO) { // ❌ 会破坏 Flow 不变性
emit(1)
}
}
// 原理:SafeCollector 会检查发射上下文
class SafeCollector {
private var lastEmissionContext: CoroutineContext? = null
suspend fun emit(value: T) {
val currentContext = coroutineContext
// 检查:emit 调用的上下文必须一致
if (lastEmissionContext != null && lastEmissionContext != currentContext) {
throw IllegalStateException("Flow invariant is violated")
}
lastEmissionContext = currentContext
// ... 发射逻辑
}
}
6. 背压处理原理
6.1 buffer 操作符实现
public fun <T> Flow<T>.buffer(
capacity: Int = Channel.BUFFERED,
onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
): Flow<T> = when (this) {
is FusibleFlow -> fuse(capacity = capacity, onBufferOverflow = onBufferOverflow)
else -> ChannelFlowOperatorImpl(
this,
capacity = capacity,
onBufferOverflow = onBufferOverflow
)
}
// ChannelFlow 的背压处理
internal abstract class ChannelFlow<T>(
val capacity: Int = Channel.BUFFERED,
val onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
) : Flow<T> {
override suspend fun collect(collector: FlowCollector<T>) {
// 创建具有缓冲能力的 channel
val channel = Channel<T>(capacity, onBufferOverflow)
// 启动生产者协程
val producer = launchProducer(channel)
// 消费者从 channel 接收
try {
for (value in channel) {
collector.emit(value)
}
} finally {
producer.cancel()
}
}
}
6.2 conflate 操作符实现
public fun <T> Flow<T>.conflate(): Flow<T> = buffer(
capacity = Channel.CONFLATED,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
// CONFLATED 的特殊处理
public const val CONFLATED: Int = -1
// Channel 实现中的 CONFLATED 处理
internal class ConflatedChannel<E> : AbstractChannel<E>() {
private var value: Any? = NULL
override suspend fun send(element: E) {
// 如果有未消费的值,直接替换
if (value !== NULL) {
value = element
} else {
// 否则正常发送
super.send(element)
}
}
}
7. SharedFlow 原理
7.1 MutableSharedFlow 核心实现
public fun <T> MutableSharedFlow(
replay: Int = 0,
extraBufferCapacity: Int = 0,
onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
): MutableSharedFlow<T> {
return SharedFlowImpl(replay, extraBufferCapacity, onBufferOverflow)
}
// SharedFlowImpl 的关键数据结构
private class SharedFlowImpl<T>(
replay: Int,
bufferCapacity: Int,
onBufferOverflow: BufferOverflow
) : AbstractSharedFlow<SharedFlowSlot<T>>(), MutableSharedFlow<T> {
// 缓冲区数组(环形缓冲区)
private var buffer: Array<Any?>? = null
private var replayIndex = 0L // 重放起始索引
private var minCollectorIndex = 0L // 最小收集者索引
// 发射值
override suspend fun emit(value: T) {
// 尝试快速发射(无等待)
if (tryEmit(value)) return
// 需要挂起等待
emitSuspend(value)
}
// 收集值
override suspend fun collect(collector: FlowCollector<T>) {
// 为收集者分配一个槽
val slot = allocateSlot()
try {
// 收集循环
while (true) {
// 尝试从缓冲区获取值
val value = slot.takeValue() ?: suspendAndWait()
collector.emit(value as T)
}
} finally {
freeSlot(slot)
}
}
}
7.2 SharedFlow 的订阅管理
// SharedFlow 的订阅者管理
abstract class AbstractSharedFlow<S : AbstractSharedFlowSlot<*>> {
// 所有活跃的订阅者槽
private var slots: Array<S?>? = null
private var nCollectors = 0
// 分配槽给新的收集者
fun allocateSlot(): S {
val slot = createSlot()
synchronized(this) {
slots = slots.orEmpty().plus(slot)
nCollectors++
onNewCollector(slot)
}
return slot
}
// 释放槽
fun freeSlot(slot: S) {
synchronized(this) {
slots = slots.orEmpty().filter { it !== slot }.toTypedArray()
nCollectors--
}
}
}
8. StateFlow 原理
8.1 StateFlow 的特殊性
public interface StateFlow<out T> : SharedFlow<T> {
public val value: T
}
// StateFlowImpl 实现
private class StateFlowImpl<T>(
initialState: T
) : AbstractSharedFlow<StateFlowSlot>(), StateFlow<T>, MutableStateFlow<T> {
private var _state: Any = initialState
private var sequence = 0L // 序列号,用于检测重复值
override val value: T
get() = _state as T
override suspend fun emit(value: T) {
// 如果值与当前状态相同,则忽略
if (this.value == value && sequence != 0L) return
// 更新状态
_state = value
sequence++
// 通知所有订阅者
forEachSlot { slot ->
slot.makePending()
}
}
}
9. Flow 的协程集成
9.1 Flow 与协程 Continuation
// Flow 收集的协程 Continuation 转换
public suspend fun <T> Flow<T>.collect(collector: FlowCollector<T>): Unit {
// 创建协程 Continuation
return suspendCoroutineUninterceptedOrReturn { cont ->
// 将 Flow 收集转换为协程挂起点
val completion = object : Continuation<Unit> {
override val context: CoroutineContext = cont.context
override fun resumeWith(result: Result<Unit>) {
// 将结果传递给原始 Continuation
cont.resumeWith(result)
}
}
// 启动 Flow 收集
startCollect(collector, completion)
}
}
9.2 Flow 的取消机制
// Flow 的取消检查
public suspend fun <T> Flow<T>.collect(collector: FlowCollector<T>) {
// 包装收集器以支持取消
val cancellableCollector = CancellableFlowCollector(collector)
try {
collectSafely(cancellableCollector)
} finally {
cancellableCollector.releaseCancellability()
}
}
// 可取消的收集器
private class CancellableFlowCollector<T>(
private val collector: FlowCollector<T>
) : FlowCollector<T> {
private var cancellationCause: Throwable? = null
override suspend fun emit(value: T) {
// 检查是否已取消
if (cancellationCause != null) {
throw CancellationException()
}
// 检查协程是否活跃
ensureActive()
// 实际发射
collector.emit(value)
}
}
10. 性能优化细节
10.1 Flow 的融合(Fusion)优化
// Flow 操作符的融合优化
public interface FusibleFlow<T> : Flow<T> {
public fun fuse(
context: CoroutineContext = EmptyCoroutineContext,
capacity: Int = Channel.OPTIONAL_CHANNEL,
onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
): Flow<T>
}
// 示例:连续 map 操作的融合
flowOf(1, 2, 3)
.map { it * 2 } // 这两个 map 可能被融合为
.map { it + 1 } // 一个 map { (it * 2) + 1 }
.collect { ... }
// 融合后的伪代码
flow {
collect { value ->
// 融合后的转换
val transformed = (value * 2) + 1
emit(transformed)
}
}
10.2 内联优化
// 许多 Flow 操作符使用 inline 优化
public inline fun <T> Flow<T>.filter(
crossinline predicate: suspend (T) -> Boolean
): Flow<T> = flow { // inline 函数,减少 lambda 对象创建
collect { value ->
if (predicate(value)) emit(value)
}
}
// 未内联的情况(性能较差):
// 1. 创建 lambda 对象
// 2. 创建新的 Flow 对象
// 3. 额外的函数调用开销
// 内联优化后:
// 1. 代码直接嵌入调用处
// 2. 减少对象创建
// 3. 更好的 JIT 优化机会
11. 总结
Kotlin Flow 的核心原理:
- 基于协程:利用挂起函数实现异步流处理
- 冷流模型:每次收集都创建新的执行
- 装饰器模式:操作符通过包装实现链式调用
- 结构化并发:自动管理资源生命周期
- 线程安全:通过 SafeCollector 确保上下文一致性
- 背压处理:基于 Channel 的缓冲机制