一、Flow 核心分类(基于 Kotlin 协程 1.7.3+ 最新规范)
Kotlin Flow 是基于协程的冷流响应式框架,核心按数据流特性分为 4 大类,各类别设计目标、生命周期、使用场景差异显著:
| 分类 | 核心特性 | 冷热属性 | 关键特征 | 典型使用场景 |
|---|---|---|---|---|
| 普通 Flow(冷流) | 被动触发:每次收集(collect)才执行上游发射逻辑,无收集则无计算 | 冷流 | 1. 无初始值;2. 多收集者各自独立执行;3. 取消收集则停止发射 | 单次数据请求(如网络接口、数据库查询) |
| StateFlow | 热流:始终持有最新值,新收集者立即获取当前值,仅发射更新后的值 | 热流 | 1. 必须有初始值;2. 仅发射与当前值不同的新值;3. 生命周期与持有者绑定 | UI 状态管理(如按钮是否可用、列表数据) |
| SharedFlow | 热流:可缓存历史值,支持多收集者共享数据,可配置重放策略 | 热流 | 1. 可选初始值;2. 支持重放历史值、限流;3. 多订阅者共享同一份数据 | 事件通知(如弹窗、Toast、导航指令) |
| Channel Flow | 基于 Channel 的 Flow:支持背压策略,适配生产者 - 消费者模型 | 冷 / 热流 | 1. 可选缓冲策略;2. 支持多生产者 / 多消费者;3. 取消后立即停止 | 高频数据生产(如传感器、实时日志) |
二、各类 Flow 详细解析(定义 + 区别 + 使用示例)
前置依赖(必加)
// 协程核心
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
// Compose 适配(如需在 Compose 中使用)
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.7.0"
1. 普通 Flow(冷流)
核心定义
最基础的 Flow,通过 flow { ... } 构建,无收集则不执行发射逻辑,每个收集者都会触发上游重新执行(比如网络请求会重复调用)。
关键区别
- 冷流:“懒加载” 特性,收集者是 “触发开关”;
- 无初始值,无缓存,取消收集后上游立即停止;
- 多收集者相互独立(A 收集和 B 收集会各自执行一次发射逻辑)。
完整使用示例
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
// 1. 构建普通 Flow(模拟网络请求/数据库查询)
fun fetchUserData(): Flow<String> = flow {
println("开始执行发射逻辑(仅当有收集者时执行)")
// 模拟耗时操作
delay(1000)
emit("用户数据1") // 发射数据
delay(500)
emit("用户数据2")
}
// 2. 使用普通 Flow
fun main() = runBlocking {
val userFlow = fetchUserData()
// 收集者1:触发第一次发射
launch {
userFlow.collect { data ->
println("收集者1接收:$data")
}
}
// 延迟2秒,确保收集者1执行完毕
delay(2000)
// 收集者2:触发第二次发射(上游逻辑重新执行)
launch {
userFlow.collect { data ->
println("收集者2接收:$data")
}
}
}
// 输出结果:
// 开始执行发射逻辑(仅当有收集者时执行)
// 收集者1接收:用户数据1
// 收集者1接收:用户数据2
// 开始执行发射逻辑(仅当有收集者时执行)
// 收集者2接收:用户数据1
// 收集者2接收:用户数据2
典型场景
- 单次异步请求(如 Retrofit 接口封装为 Flow);
- 一次性数据计算(如解析本地文件)。
2. StateFlow(热流)
核心定义
StateFlow 是 SharedFlow 的特化版,始终持有最新值,适合存储 “状态”(如 UI 显示的文本、开关状态)。
关键区别
- 热流:无论是否有收集者,只要更新值就会存储(但仅当有收集者时发射);
- 必须有初始值,仅发射与当前值不同的新值(避免重复更新);
- 多收集者共享同一份最新值(新收集者立即获取当前值)。
完整使用示例
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
// 1. 构建 StateFlow(UI 状态管理示例)
class UiStateManager {
// 私有可变 StateFlow(仅内部可更新)
private val _uiState = MutableStateFlow<String>("初始状态")
// 公开不可变 StateFlow(外部仅可收集)
val uiState: StateFlow<String> = _uiState.asStateFlow()
// 更新状态
fun updateState(newState: String) {
_uiState.value = newState // StateFlow 用 value 更新值
}
}
// 2. 使用 StateFlow
fun main() = runBlocking {
val stateManager = UiStateManager()
// 收集者1:立即接收初始值,后续接收更新值
launch {
stateManager.uiState.collect { state ->
println("收集者1接收状态:$state")
}
}
// 延迟500ms,更新状态
delay(500)
stateManager.updateState("加载中")
// 延迟500ms,添加收集者2(立即接收最新值“加载中”)
delay(500)
launch {
stateManager.uiState.collect { state ->
println("收集者2接收状态:$state")
}
}
// 延迟500ms,更新重复值(不会发射,因为与当前值相同)
delay(500)
stateManager.updateState("加载中")
// 延迟500ms,更新新值
delay(500)
stateManager.updateState("加载完成")
}
// 输出结果:
// 收集者1接收状态:初始状态
// 收集者1接收状态:加载中
// 收集者2接收状态:加载中
// 收集者1接收状态:加载完成
// 收集者2接收状态:加载完成
Compose 中使用(最新 API)
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsStateWithLifecycle
import androidx.compose.material3.Text
@Composable
fun StateFlowComposeDemo(manager: UiStateManager) {
// 自动感知生命周期,后台暂停收集
val uiState by manager.uiState.collectAsStateWithLifecycle()
Text(text = "当前状态:$uiState")
}
典型场景
- Compose/Android 页面状态管理(如标题文本、列表数据、按钮是否禁用);
- ViewModel 中存储 UI 相关的可变状态。
3. SharedFlow(热流)
核心定义
通用型热流,支持缓存历史值、配置重放策略、限流,适合传递 “事件”(如弹窗通知、导航指令)。
关键区别
- 热流:无初始值(可选),可配置重放历史值数量;
- 支持多收集者共享数据,可设置 “额外缓冲区” 和 “限流策略”;
- 不过滤重复值(与 StateFlow 核心区别)。
核心参数说明
// MutableSharedFlow 构建参数
MutableSharedFlow<T>(
replay = 0, // 重放历史值数量(新收集者接收的历史值数)
extraBufferCapacity = 0, // 额外缓冲区大小(超出则触发限流策略)
onBufferOverflow = BufferOverflow.SUSPEND // 限流策略:SUSPEND(挂起)/DROP_OLDEST/DROP_LATEST
)
完整使用示例
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
// 1. 构建 SharedFlow(事件通知示例)
class EventManager {
// 配置:重放1条历史事件,额外缓冲区2,超出则丢弃最旧事件
private val _eventFlow = MutableSharedFlow<String>(
replay = 1,
extraBufferCapacity = 2,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
val eventFlow: SharedFlow<String> = _eventFlow.asSharedFlow()
// 发送事件
suspend fun sendEvent(event: String) {
_eventFlow.emit(event) // SharedFlow 用 emit 发射(挂起函数)
}
}
// 2. 使用 SharedFlow
fun main() = runBlocking {
val eventManager = EventManager()
// 先发送2个事件(此时无收集者,replay=1 会缓存最后1个)
eventManager.sendEvent("事件1")
eventManager.sendEvent("事件2")
// 收集者1:立即接收重放的1个历史事件(事件2)
launch {
eventManager.eventFlow.collect { event ->
println("收集者1接收事件:$event")
}
}
delay(500)
// 发送3个事件(超出缓冲区:replay=1 + extraBufferCapacity=2 = 3,第4个会触发限流)
repeat(4) {
eventManager.sendEvent("新事件$it")
delay(100)
}
// 收集者2:接收重放的1个历史事件(最后1个新事件)
delay(500)
launch {
eventManager.eventFlow.collect { event ->
println("收集者2接收事件:$event")
}
}
}
// 输出结果:
// 收集者1接收事件:事件2
// 收集者1接收事件:新事件0
// 收集者1接收事件:新事件1
// 收集者1接收事件:新事件2
// 收集者1接收事件:新事件3
// 收集者2接收事件:新事件3
Compose 中使用
@Composable
fun SharedFlowComposeDemo(manager: EventManager) {
// 收集事件(推荐在 LaunchedEffect 中收集,避免重组重复收集)
LaunchedEffect(Unit) {
manager.eventFlow.collect { event ->
// 处理事件(如弹Toast、导航)
println("处理事件:$event")
}
}
}
典型场景
- 跨页面 / 组件的事件通知(如弹窗、Toast、错误提示);
- 导航指令(如从 ViewModel 通知页面跳转到详情页);
- 实时消息推送(如聊天消息、系统通知)。
4. Channel Flow(通道流)
核心定义
基于 Channel 实现的 Flow,适配生产者 - 消费者模型,支持自定义背压策略,可作为 “冷流” 或 “热流” 使用。
关键区别
- 支持多生产者、多消费者;
- 可配置缓冲策略(与 SharedFlow 类似,但更底层);
- 取消收集后立即停止发射,适合高频数据生产。
完整使用示例
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
// 1. 构建 Channel Flow(模拟传感器数据采集)
fun sensorDataFlow(): Flow<Int> = channelFlow {
// 生产者1:模拟传感器1数据
launch {
repeat(3) {
send(it * 10) // 发送数据到通道
delay(200)
}
}
// 生产者2:模拟传感器2数据
launch {
repeat(3) {
send(it * 100)
delay(300)
}
}
// 延迟1秒后关闭通道
delay(1000)
close()
}
// 2. 使用 Channel Flow
fun main() = runBlocking {
sensorDataFlow().collect { data ->
println("接收传感器数据:$data")
}
}
// 输出结果(顺序由延迟决定):
// 接收传感器数据:0
// 接收传感器数据:0
// 接收传感器数据:10
// 接收传感器数据:100
// 接收传感器数据:20
// 接收传感器数据:200
典型场景
- 高频数据生产(如传感器数据、实时日志、串口数据);
- 多生产者向同一消费者发送数据;
- 需要精细控制背压策略的场景。
三、各类 Flow 核心区别总结表
| 特性 | 普通 Flow | StateFlow | SharedFlow | Channel Flow |
|---|---|---|---|---|
| 冷热属性 | 冷流 | 热流 | 热流 | 冷 / 热流 |
| 初始值 | 无 | 必须有 | 可选 | 无 |
| 重复值过滤 | 无 | 过滤(仅发射不同值) | 不过滤 | 不过滤 |
| 多收集者 | 各自独立执行 | 共享最新值 | 共享历史 / 新值 | 共享通道数据 |
| 缓存 / 重放 | 无 | 仅最新值 | 可配置重放数量 | 可配置缓冲区 |
| 核心用途 | 单次数据请求 | UI 状态管理 | 事件通知 | 生产者 - 消费者模型 |
| 发射方式 | emit() | value = ... | emit() | send() |
| Compose 推荐用法 | collectAsStateWithLifecycle | collectAsStateWithLifecycle | LaunchedEffect 中 collect | collectAsStateWithLifecycle |
四、使用原则与最佳实践
-
状态用 StateFlow,事件用 SharedFlow:
- UI 状态(如文本、开关)→ StateFlow;
- 一次性事件(如弹窗、导航)→ SharedFlow(replay=0,避免重复处理)。
-
普通 Flow 仅用于单次请求:如网络接口、数据库查询,避免用于持续更新的场景(否则每次收集都会重复请求)。
-
避免 SharedFlow 滥用 replay:事件类 SharedFlow 建议
replay=0,防止新页面接收历史事件导致重复处理。 -
Compose 中收集注意事项:
- StateFlow:用
collectAsStateWithLifecycle转为 State,自动重组; - SharedFlow:在
LaunchedEffect中收集,避免重组导致重复订阅; - 普通 Flow:用
collectAsStateWithLifecycle,后台自动暂停收集。
- StateFlow:用
-
异常处理:所有 Flow 收集时必须加
catch处理异常,避免崩溃:
flow.catch { e ->
Log.e("FlowError", "收集失败", e)
// 兜底值
emit(-1)
}.collect { ... }
五、核心总结
- 普通 Flow:冷流,单次请求首选,无收集则不执行,多收集者独立;
- StateFlow:热流,状态管理首选,有初始值、过滤重复值,多收集者共享最新值;
- SharedFlow:热流,事件通知首选,可配置重放 / 缓冲区,不过滤重复值;
- Channel Flow:底层通道流,适配生产者 - 消费者模型,支持多生产者 / 多消费者。
选择 Flow 类型的核心原则:状态用 StateFlow,事件用 SharedFlow,单次请求用普通 Flow,高频生产用 Channel Flow。