一、冷流(Cold Flow)
特点:
- 按需触发:只有调用
collect()
时,才开始生产数据。 - 独立副本:每个新的订阅者都会触发完整的数据流从头开始。
- 典型代表:
flow { ... }
、asFlow()
。
冷流示例代码:
//每次collect都会重新发射数据
val coldFlow = flow {
println("开始生产数据") //每次collect都会执行
emit(1)
emit(2)
}
// 第一个订阅者
coldFlow.collect { println("订阅者1: $it") } // 输出:1,2
// 第二个订阅者
coldFlow.collect { println("订阅者2: $it") } // 再次输出:1,2
适用场景:
- 如网络请求、数据库查询,即需要独立数据源场景。
- 每个订阅者需要从头消费完整的数据。
总结:
冷流像【点播电影】,你点播才开始播放,不同观众各自从头开始看。
二、热流(Hot Flow)
特点:
- 主动发射:不管有没有订阅者,数据都会产生。
- 共享数据源:多个订阅者共享同一份数据流,但只能收到订阅后的数据。
- 典型代表:
SharedFlow
、StateFlow
。
热流示例代码:
// 创建热流(SharedFlow)
val hotFlow = MutableSharedFlow<Int>()
// 启动协程持续发射数据(即使没有订阅者)
CoroutineScope(Dispatchers.Default).launch {
repeat(3) {
delay(1000)
// 发射 0 1 2
hotFlow.emit(it)
}
}
// 第一个订阅者(延迟1秒订阅)
CoroutineScope(Dispatchers.Main).launch {
delay(1000)
hotFlow.collect { println("订阅者1: $it") } // 只能收到 1,2
}
// 第二个订阅者(延迟5秒订阅)
CoroutineScope(Dispatchers.Main).launch {
delay(5000)
hotFlow.collect { println("订阅者2: $it") } // 收不到任何数据(发射已结束)
}
适用场景:
- 需要共享实时数据的场景(如IM消息、用户定位更新)。
- 多个订阅者需要获取同一份动态数据(如全局状态管理)。
总结:
热流像【直播】,不管你看不看,节目都在进行,中途进入的只能从当前内容开始看。
三、 冷流(Cold Flow) vs 热流(Hot Flow)
冷流(Cold Flow) | 热流(Hot Flow) | |
---|---|---|
数据发射时机 | 按需触发(有订阅才发射) | 主动发射(不管有没有订阅) |
数据独立性 | 每个订阅者获取独立副本 | 所有订阅者共享同一数据源 |
数据历史 | 新订阅者从头获取完整数据 | 新订阅者只能获取订阅后的数据 |
典型用例 | 单次网络请求、文件读取 | 实时状态更新、事件总线 |
资源消耗 | 每次订阅都重新执行逻辑(重复耗时) | 单次数据源共享(节约资源) |
开发中如何选择使用冷/热流?
冷流(私人订制)
:
- 每个订阅者需要独立完整的数据(如每次打开页面都重新请求最新数据)。
- 数据生产逻辑需要按需触发(如按钮点击才加载数据)。
热流(直播)
:
- 需要多个订阅者共享实时数据(如全局登录状态)。
- 数据生产是持续且独立的(如实时定位数据、传感器数据、WebSocket消息)。