深入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 的关键特性:
-
状态管理
- 使用原子引用存储状态
- 支持 CAS 操作
- 序列化状态更新
-
值合并
- 使用相等性检查避免重复发射
- 只发射变化的值
- 保证最新值的传递
-
线程安全
- 同步块保护状态更新
- 锁外触发值更新避免死锁
- 序列号管理并发更新
-
性能优化
- 快速路径避免不必要的挂起
- 合并重复值减少开销
- 高效的订阅者管理
4. 关键机制解析
-
缓冲区管理
- 使用循环数组实现缓冲区
- 通过 head 和 size 管理数据范围
- 支持动态扩容
-
收集者管理
- 使用 Slot 数组管理收集者
- 每个收集者维护自己的消费位置
- 通过 minCollectorIndex 跟踪最慢的收集者
-
发射机制
- 快速路径:直接写入缓冲区
- 慢路径:挂起等待缓冲区空间
- 支持不同的溢出策略
-
重放机制
- 维护固定大小的重放缓存
- 新订阅者从 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. 最佳实践
-
择合适的 Flow 类型
- 使用
StateFlow存储状态 - 使用
SharedFlow处理事件 - 使用普通
Flow处理数据流
- 使用
-
异常处理策略
- 在适当的位置使用
catch - 考虑重试机制
- 提供错误恢复机制
- 在适当的位置使用
-
生命周期管理
- 使用适当的协程作用域
- 正确处理取消
- 及时清理资源