跳转到正文
YGJoon
返回

Android Kotlin Flow 高级操作符与背压控制

编辑文章

高级操作符分类

类别操作符示例说明
合并zip、combine、merge多 Flow 合并或同步发射
展开flatMapConcat、flatMapLatest、flatMapMerge控制内层 Flow 执行方式
背压控制buffer、conflate、collectLatest管理上下游速度差异
时间操作debounce、sample、timeout处理节流、防抖

合并策略

val userFlow = repository.observeUser()
val configFlow = repository.observeConfig()

val uiState: Flow<UiState> = combine(userFlow, configFlow) { user, config ->
    UiState(user, config)
}

val zipped = userFlow.zip(configFlow) { user, config ->
    user to config
}

flatMap 系列

操作符特点
flatMapConcat顺序执行,等待前一个完成
flatMapMerge并行收集,最多 concurrency 个
flatMapLatest取消上一个,保留最新子流
// 搜索建议:保留最新输入
searchText
    .debounce(300)
    .flatMapLatest { keyword -> repository.search(keyword) }
    .collect { result -> render(result) }

背压策略

buffer

flowOnIo()
    .buffer(capacity = Channel.BUFFERED)
    .collect { process(it) }

conflate

stateFlow
    .conflate()
    .collect { latest -> render(latest) }

collectLatest

events.collectLatest { event ->
    delay(500) // 新事件到来时终止旧任务
}

Flow 与外部系统

1. Callback 转换

fun View.clicks(): Flow<Unit> = callbackFlow {
    setOnClickListener { trySend(Unit) }
    awaitClose { setOnClickListener(null) }
}

2. Room + Flow

@Dao
interface ArticleDao {
    @Query("SELECT * FROM article ORDER BY time DESC")
    fun observeArticles(): Flow<List<ArticleEntity>>
}

dao.observeArticles()
    .flowOn(Dispatchers.IO)
    .map { it.map(ArticleEntity::toDomain) }

错误处理

flow {
    emit(api.load())
}.retryWhen { cause, attempt ->
    (cause is IOException && attempt < 3).also { if (it) delay(2_000) }
}.catch { emit(handleError(it)) }

性能建议

测试策略

@Test
fun `flatMapLatest cancels previous`() = runTest {
    val results = mutableListOf<String>()
    val flow = MutableSharedFlow<String>()

    val job = launch {
        flow.flatMapLatest { value -> flowOf(value).onEach { delay(100) } }
            .collect { results += it }
    }

    flow.emit("A")
    flow.emit("B")
    advanceUntilIdle()
    assertEquals(listOf("B"), results)
    job.cancel()
}

常见问题

问题原因解决方案
数据闪烁下游处理慢,上游不断发射使用 conflate 或 collectLatest
订阅不到数据shareIn 范围不正确将 scope 设置为 viewModelScope 等长生命周期
内存泄漏callbackFlow 未关闭 channel在 awaitClose 中释放资源

总结

  1. 合理选择 flatMap、combine 等操作符是构建 Flow 数据流的关键。
  2. 背压策略决定上游和下游的协调方式,需根据场景(UI、网络)灵活选取。
  3. 与外部系统整合时,注意生命周期与资源释放,确保 Flow 数据流稳定可靠。

编辑文章
分享这篇文章:

上一篇
Android Kotlin Gradle Kotlin DSL 与构建优化
下一篇
Android Kotlin Flow 数据流与状态管理