Administrator
发布于 2026-08-25 / 20 阅读
0
0

系列文章《Android 工程师的 100 篇进阶笔记》第 18 篇:Kotlin Flow:冷流、热流、背压与 SharedFlow/StateFlow

前面聊过协程和挂起函数,实际工程中真正高频出现的是 Flow。它把响应式编程带进了 Kotlin,但很多人用了一段时间还是分不清冷流和热流。


一、冷流:只有收集者才触发发射

fun coldFlow(): Flow<Int> = flow {
    println("flow started")
    for (i in 1..3) {
        emit(i)
    }
}

// 两个 collect,flow 会执行两次
coldFlow().collect { println(it) }
coldFlow().collect { println(it) }

flow { } 构建的是冷流。每次 collect,上游代码都会重新执行。这和 RxJava 的 Observable 不一样,更像是 RxJava 的 defer。


二、热流:状态常驻,多个订阅者共享

热流用 SharedFlow 和 StateFlow。

private val _events = MutableSharedFlow<String>()
val events: SharedFlow<String> = _events

private val _state = MutableStateFlow(0)
val state: StateFlow<Int> = _state.asStateFlow()

特性

SharedFlow

StateFlow

默认缓存

0 个

1 个最新值

是否需要初始值

不需要

需要

典型用途

一次性事件,如 Toast、导航

UI 状态,如 loading、data


三、背压:生产快、消费慢怎么办

flow {
    for (i in 1..10_000) emit(i)
}
    .buffer()          // 缓冲,发射不等待消费
    .conflate()        // 只保留最新值,跳过中间值
    .collectLatest { } // 有新值时取消旧值处理

背压策略要按业务选:

  • 实时性要求高 → collectLatest

  • 不能丢数据 → buffer 或 channelFlow

  • 允许采样 → conflate 或 sample


四、Flow 与生命周期

@Composable
fun UserScreen(viewModel: UserViewModel = viewModel()) {
    val users by viewModel.users.collectAsStateWithLifecycle()
}

collectAsStateWithLifecycle 会在 App 进入后台时自动停止收集,避免无效更新和内存泄漏。


五、常见反模式

  1. 把一次性事件存在 StateFlow 里:StateFlow 会重放最新值,事件重复消费容易出错。事件用 SharedFlow。

  2. 在 Flow 里做耗时操作不切换线程:Flow 默认跑在收集者所在线程,记得用 flowOn(Dispatchers.IO)。

  3. 用 stateIn 时没指定 SharingStarted:默认 Eagerly 会立即启动,后台也会跑。通常用 WhileSubscribed(5000)。

val state = repository.loadData()
    .stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5000),
        initialValue = emptyList()
    )

小结

  1. 冷流按需启动,热流常驻共享

  2. 事件用 SharedFlow,状态用 StateFlow

  3. 背压策略根据实时性 vs 完整性选

  4. 用 lifecycle-aware 的收集方式,避免内存泄漏

下一篇,我们回到 UI 动效,看看 Android 属性动画和 MotionLayout 怎么做出顺滑的交互。


参考阅读

引用链接

[1]Kotlin Flow 官方文档: https://kotlinlang.org/docs/flow.html

[2]StateFlow and SharedFlow: https://developer.android.com/kotlin/flow/stateflow-and-sharedflow


评论