kotlin flow的简单了解

43 阅读9分钟

一、简单用法

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 的核心原理:

  1. 基于协程:利用挂起函数实现异步流处理
  2. 冷流模型:每次收集都创建新的执行
  3. 装饰器模式:操作符通过包装实现链式调用
  4. 结构化并发:自动管理资源生命周期
  5. 线程安全:通过 SafeCollector 确保上下文一致性
  6. 背压处理:基于 Channel 的缓冲机制