深入Kotlin-协程 Flow 详解

792 阅读3分钟

深入Kotlin-协程 Flow 详解

一、Flow 简介

Flow 是 Kotlin 协程库提供的冷流 API,用于处理异步数据流。它是一种响应式编程的实现,特别适合处理连续的数据更新场景。

1. 冷流与热流

1.1 冷流 (Flow)
  • 每个收集者都会触发流的重新执行
  • 不会主动发射数据,只在被收集时才开始发射
  • 适用于需要按需获取数据的场景
// 冷流示例
val coldFlow = flow {
    println("开始执行流")
    for (i in 1..3) {
        delay(100)
        emit(i)
    }
}

// 每次收集都会重新执行
suspend fun collectColdFlow() {
    coldFlow.collect { println("第一次收集: $it") }
    coldFlow.collect { println("第二次收集: $it") } // 会重新执行流
}
1.2 热流 (SharedFlow/StateFlow)
  • 可以有多个订阅者共享同一个数据流
  • 即使没有收集者也会发射数据
  • 适用于需要广播数据的场景
// StateFlow示例
class ViewModel {
    private val _state = MutableStateFlow(0)
    val state: StateFlow<Int> = _state.asStateFlow()
    
    fun updateState() {
        _state.value = _state.value + 1
    }
}

// SharedFlow示例
class EventBus {
    private val _events = MutableSharedFlow<Event>()
    val events = _events.asSharedFlow()
    
    suspend fun emit(event: Event) {
        _events.emit(event)
    }
}

2. 常用场景

2.1 网络请求
class Repository {
    fun getDataStream(): Flow<Data> = flow {
        while (true) {
            val data = api.fetchData()
            emit(data)
            delay(1000) // 每秒更新一次
        }
    }
}
2.2 数据库观察
class RoomRepository {
    fun observeItems(): Flow<List<Item>> = 
        database.itemDao().observeAll()
            .distinctUntilChanged()
            .flowOn(Dispatchers.IO)
}
2.3 UI 事件处理
class UserViewModel {
    private val _uiEvents = MutableSharedFlow<UiEvent>()
    val uiEvents = _uiEvents.asSharedFlow()
    
    fun handleClick() {
        viewModelScope.launch {
            _uiEvents.emit(UiEvent.ShowDialog)
        }
    }
}

二、多流操作

1. 组合操作

1.1 zip
// 组合两个流,一一对应
val flow1 = flowOf(1, 2, 3)
val flow2 = flowOf("a", "b", "c")

flow1.zip(flow2) { number, letter ->
    "$number$letter"
}.collect { println(it) } // 输出:1a, 2b, 3c
1.2 combine
// 任一流更新都会触发组合
val flow1 = MutableStateFlow(1)
val flow2 = MutableStateFlow("a")

flow1.combine(flow2) { number, letter ->
    "$number$letter"
}.collect { println(it) }

flow1.value = 2 // 触发组合:2a
flow2.value = "b" // 触发组合:2b

2. 转换操作

2.1 map/transform
val numberFlow = flow {
    emit(1)
    emit(2)
    emit(3)
}

// 使用 map 转换
numberFlow
    .map { it * 2 }
    .collect { println(it) } // 输出:2, 4, 6

// 使用 transform 自定义转换
numberFlow
    .transform { value ->
        emit("Number: $value")
        emit("Double: ${value * 2}")
    }
    .collect { println(it) }
2.2 flatMapConcat/flatMapMerge/flatMapLatest
// flatMapConcat:按顺序处理
flow {
    emit(1)
    emit(2)
}.flatMapConcat { value ->
    flow {
        emit("Start $value")
        delay(100)
        emit("End $value")
    }
}.collect { println(it) }

// flatMapMerge:并发处理
flow {
    emit(1)
    emit(2)
}.flatMapMerge { value ->
    flow {
        emit("Processing $value")
        delay(Random.nextLong(100))
        emit("Done $value")
    }
}.collect { println(it) }

// flatMapLatest:只处理最新值
flow {
    emit(1)
    delay(50)
    emit(2)
}.flatMapLatest { value ->
    flow {
        delay(100)
        emit("Result $value")
    }
}.collect { println(it) } // 只输出:Result 2

三、Flow 原理

1. SharedFlow 源码分析

internal class SharedFlowImpl<T>(
    private val replay: Int,
    private val bufferCapacity: Int,
    private val onBufferOverflow: BufferOverflow
) : AbstractSharedFlow<SharedFlowSlot>(), MutableSharedFlow<T> {
    // 存储数据的缓冲区
    private var buffer: Array<Any?>? = null 
    // 新订阅者开始收集的位置
    private var replayIndex = 0L 
    // 最慢的收集者的位置
    private var minCollectorIndex = 0L 
    // 缓冲区中的数据数量
    private var bufferSize = 0 
    // 等待发射的数据数量
    private var queueSize = 0 

    // 计算属性
    private val head: Long get() = minOf(minCollectorIndex, replayIndex)
    private val replaySize: Int get() = (head + bufferSize - replayIndex).toInt()
    private val totalSize: Int get() = bufferSize + queueSize
    private val bufferEndIndex: Long get() = head + bufferSize
    private val queueEndIndex: Long get() = head + bufferSize + queueSize

    override suspend fun collect(collector: FlowCollector<T>) {
        val slot = allocateSlot()
        try {
            if (collector is SubscribedFlowCollector) {
                collector.onSubscription()
            }
            val collectorJob = currentCoroutineContext()[Job]
            while (true) {
                var newValue: Any?
                while (true) {
                    // 尝试无挂起快速获取值
                    newValue = tryTakeValue(slot) 
                    if (newValue !== NO_VALUE) break
                    // 等待新值
                    awaitValue(slot) 
                }
                collectorJob?.ensureActive()
                
                collector.emit(newValue as T)
            }
        } finally {
            freeSlot(slot)
        }
    }

    override suspend fun emit(value: T) {
        // 快速路径:尝试无挂起发射
        if (tryEmit(value)) return 
        // 慢路径:需要挂起
        emitSuspend(value)
    }

    private fun tryEmitLocked(value: T): Boolean {
        // 无收集者时的快速路径
        if (nCollectors == 0) {
            return tryEmitNoCollectorsLocked(value)
        }
        
        // 检查缓冲区是否已满
        if (bufferSize >= bufferCapacity && 
            minCollectorIndex <= replayIndex) {
            when (onBufferOverflow) {
                BufferOverflow.SUSPEND -> return false
                BufferOverflow.DROP_LATEST -> return true
                BufferOverflow.DROP_OLDEST -> {} 
            }
        }
        
        // 将值添加到缓冲区
        enqueueLocked(value)
        bufferSize++
        
        // 如果缓冲区超出容量,丢弃最旧的值
        if (bufferSize > bufferCapacity) {
            dropOldestLocked()
        }
        
        // 维护 replay 大小
        if (replaySize > replay) {
            updateBufferLocked(replayIndex + 1, 
                minCollectorIndex, 
                bufferEndIndex, 
                queueEndIndex)
        }
        return true
    }
}

2. StateFlow 源码分析

private class StateFlowImpl<T>(
    initialState: Any // T | NULL
) : AbstractSharedFlow<SharedFlowSlot>(), MutableStateFlow<T> {
    // 原子引用存储状态
    private val _state = atomic(initialState)
    // 序列号,用于序列化更新,序列号为奇数时表示更新正在进行
    private var sequence = 0
    
    @Suppress("UNCHECKED_CAST")
    override var value: T
        get() = NULL.unbox(_state.value)
        set(value) { 
            updateState(null, value ?: NULL) 
        }
    
    override fun compareAndSet(expect: T, update: T): Boolean =
        updateState(expect ?: NULL, update ?: NULL)
    
    private fun updateState(expectedState: Any?, newState: Any): Boolean {
        var curSequence = 0
        var curSlots: Array<StateFlowSlot?>? = this.slots
        synchronized(this) {
            val oldState = _state.value
            // CAS 检查
            if (expectedState != null && oldState != expectedState) return false
            // 值未改变,直接返回
            if (oldState == newState) return true
            
            // 更新状态
            _state.value = newState
            curSequence = sequence
            
            // 序列号为偶数表示静止状态
            if (curSequence and 1 == 0) {
                curSequence++ // 变为奇数
                sequence = curSequence
            } else {
                // 更新已在进行中,通知并返回
                sequence = curSequence + 2
                return true
            }
            curSlots = slots
        }
        
        // 在锁外触发值更新,避免死锁
        while (true) {
            curSlots?.forEach {
                it?.makePending()
            }
            
            synchronized(this) {
                if (sequence == curSequence) {
                    sequence = curSequence + 1 // 变回偶数
                    return true
                }
                curSequence = sequence
                curSlots = slots
            }
        }
    }
    
    override suspend fun collect(collector: FlowCollector<T>) {
        val slot = allocateSlot()
        try {
            if (collector is SubscribedFlowCollector) collector.onSubscription()
            val collectorJob = currentCoroutineContext()[Job]
            var oldState: Any? = null // 之前发射的值
            
            // 循环开始时直接发送当前值,无需等待
            while (true) {
                // 获取最新状态,确保获取最新值以实现最佳的值合并
                val newState = _state.value
                // 检查取消状态
                collectorJob?.ensureActive()
                
                // 使用相等性检查合并值的发射
                if (oldState == null || oldState != newState) {
                    collector.emit(NULL.unbox(newState))
                    oldState = newState
                }
                
                // 如果 awaitPending 被取消,会跳出循环并调用 freeSlot
                if (!slot.takePending()) { // 先尝试无挂起快速路径
                    slot.awaitPending() // 只在需要新值时挂起
                }
            }
        } finally {
            freeSlot(slot)
        }
    }
    
    override val replayCache: List<T>
        get() = listOf(value)
    
    override fun tryEmit(value: T): Boolean {
        this.value = value
        return true
    }
    
    override suspend fun emit(value: T) {
        this.value = value
    }
    
    override fun resetReplayCache() {
        throw UnsupportedOperationException(
            "MutableStateFlow.resetReplayCache is not supported"
        )
    }
}

3. StateFlow 的关键特性:

  1. 状态管理

    • 使用原子引用存储状态
    • 支持 CAS 操作
    • 序列化状态更新
  2. 值合并

    • 使用相等性检查避免重复发射
    • 只发射变化的值
    • 保证最新值的传递
  3. 线程安全

    • 同步块保护状态更新
    • 锁外触发值更新避免死锁
    • 序列号管理并发更新
  4. 性能优化

    • 快速路径避免不必要的挂起
    • 合并重复值减少开销
    • 高效的订阅者管理

4. 关键机制解析

  1. 缓冲区管理

    • 使用循环数组实现缓冲区
    • 通过 head 和 size 管理数据范围
    • 支持动态扩容
  2. 收集者管理

    • 使用 Slot 数组管理收集者
    • 每个收集者维护自己的消费位置
    • 通过 minCollectorIndex 跟踪最慢的收集者
  3. 发射机制

    • 快速路径:直接写入缓冲区
    • 慢路径:挂起等待缓冲区空间
    • 支持不同的溢出策略
  4. 重放机制

    • 维护固定大小的重放缓存
    • 新订阅者从 replayIndex 开始收集
    • 自动管理重放窗口大小

5. 操作符实现原理

// map 操作符实现
public fun <T, R> Flow<T>.map(transform: suspend (value: T) -> R): Flow<R> = 
    MapOperator(this, transform)

private class MapOperator<T, R>(
    private val upstream: Flow<T>,
    private val transform: suspend (T) -> R
) : Flow<R> {
    override suspend fun collect(collector: FlowCollector<R>) {
        upstream.collect { value ->
            // 转换并发射值
            collector.emit(transform(value))
        }
    }
}

// filter 操作符实现
public fun <T> Flow<T>.filter(predicate: suspend (T) -> Boolean): Flow<T> = 
    FilterOperator(this, predicate)

private class FilterOperator<T>(
    private val upstream: Flow<T>,
    private val predicate: suspend (T) -> Boolean
) : Flow<T> {
    override suspend fun collect(collector: FlowCollector<T>) {
        upstream.collect { value ->
            if (predicate(value)) {
                collector.emit(value)
            }
        }
    }
}

6. 上下文保存机制

// 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)
        safeCollector.block()
    }
}

internal class SafeCollector<T>(
    private val collector: FlowCollector<T>,
    private val collectContext: CoroutineContext
) : FlowCollector<T> {
    private var lastEmissionContext: CoroutineContext? = null
    
    override suspend fun emit(value: T) {
        // 检查发射上下文
        val currentContext = currentCoroutineContext()
        if (lastEmissionContext !== currentContext) {
            // 验证上下文
            checkContext(currentContext)
            lastEmissionContext = currentContext
        }
        // 发射值
        collector.emit(value)
    }
    
    private fun checkContext(currentContext: CoroutineContext) {
        // 确保在正确的调度器上执行
        val collectJob = collectContext[Job]
        val emissionJob = currentContext[Job]
        if (!emissionJob.isChildOf(collectJob)) {
            throw IllegalStateException(
                "Flow invariant is violated:\n" +
                "\t\tEmission context: $currentContext\n" +
                "\t\tCollection context: $collectContext"
            )
        }
    }
}

7. 取消机制

// CancellableFlow 实现
internal class CancellableFlow<T>(
    private val upstream: Flow<T>
) : Flow<T> {
    override suspend fun collect(collector: FlowCollector<T>) {
        upstream.collect { value ->
            // 检查协程是否活跃
            currentCoroutineContext().ensureActive()
            collector.emit(value)
        }
    }
}

// 取消检查扩展函数
public fun <T> Flow<T>.cancellable(): Flow<T> = when (this) {
    is CancellableFlow -> this
    else -> CancellableFlow(this)
}

四、常见题

1. 背压处理

class BackpressureExample {
    fun handleBackpressure() = flow {
        for (i in 1..1000) {
            emit(i)
        }
    }
        .buffer(50) // 缓冲区
        .conflate() // 合并发射值
        .collectLatest { value -> // 只处理最新值
            delay(100) // 模拟耗时处理
            println("Processing $value")
        }
}

2. 异常处理

fun exceptionHandling() = flow {
    emit(1)
    throw RuntimeException("Error")
}
    .catch { e -> 
        // 处理上游异常
        emit(-1)
    }
    .onCompletion { cause ->
        // 流完成或取消时调用
        println("Completed with $cause")
    }
    .retryWhen { cause, attempt ->
        // 重试逻辑
        attempt < 3 && cause is NetworkException
    }

3. 生命周期处理

class FlowViewModel : ViewModel() {
    private val _data = MutableStateFlow<UiState>(UiState.Initial)
    val data = _data.asStateFlow()
    
    fun loadData() {
        viewModelScope.launch {
            repository.getData()
                .onStart { _data.value = UiState.Loading }
                .catch { e -> _data.value = UiState.Error(e) }
                .collect { result ->
                    _data.value = UiState.Success(result)
                }
        }
    }
}

// Activity/Fragment中使用
class MyActivity : AppCompatActivity() {
    private val viewModel: FlowViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        lifecycleScope.launch {
            // 在生命周期范围内收集
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.data.collect { state ->
                    updateUi(state)
                }
            }
        }
    }
}

五、注意事项

1. 线程安全

// Main
// 确保在正确的调度器上执行
fun safeFlow() = flow {
    // 耗时的数据生成操作 IO
    }.flowOn(Dispatchers.IO)  // IO密集型操作使用IO调度器
    .map { 
        // 复杂的数据处理 Default
    }.flowOn(Dispatchers.Default)  // CPU密集型操作使用Default调度器
    .collect { 
        // UI更新操作
    } // 在Main线程收集

2. 内存泄漏防范

class SafeViewModel : ViewModel() {
    private val job = SupervisorJob()
    
    init {
        viewModelScope.launch(job) {
            dataFlow
                .onCompletion { 
                    // 清理资源
                }
                .collect { /* 处理数据 */ }
        }
    }
    
    override fun onCleared() {
        super.onCleared()
        job.cancel() // 取消所有协程
    }
}

3. 性能优化

fun optimizedFlow() = flow {
    // 1. 使用适当的缓冲区大小
    buffer(DEFAULT_BUFFER_SIZE)
    
    // 2. 合理使用操作符
    distinctUntilChanged() // 避免重复值
    debounce(300) // 防抖
    
    // 3. 使用适当的作用域
    flowOn(Dispatchers.Default)
}

4. 测试

class FlowTest {
    @Test
    fun testFlow() = runTest {
        val flow = flow {
            emit(1)
            emit(2)
            emit(3)
        }
        
        val results = mutableListOf<Int>()
        flow.toList(results)
        
        assertEquals(listOf(1, 2, 3), results)
    }
}

5. 最佳实践

  1. 择合适的 Flow 类型

    • 使用 StateFlow 存储状态
    • 使用 SharedFlow 处理事件
    • 使用普通 Flow 处理数据流
  2. 异常处理策略

    • 在适当的位置使用 catch
    • 考虑重试机制
    • 提供错误恢复机制
  3. 生命周期管理

    • 使用适当的协程作用域
    • 正确处理取消
    • 及时清理资源