在Android开发中,Flow是Kotlin协程库提供的一个核心组件,用于处理异步数据流。它是一种冷流(cold stream),意味着数据生产仅在有收集者(collector)调用collect时开始,并按顺序发射多个值。
基本概念与核心特点
-
冷流特性:Flow是冷的,只有当调用collect方法时才会启动数据生产流程。每个收集者都会触发完整的数据流从头开始。
-
异步多值发射:通过flow构建器定义数据源,使用emit函数发射值,支持挂起函数(如delay)实现非阻塞异步操作。
-
操作符链式调用:支持中间操作符(如map、filter)对数据流进行转换和过滤,末端操作符(如collect)启动收集流程。
基础用法示例
bash
// 定义一个Flow,异步发射数字1、2、3,间隔1秒
val numbersFlow = flow {
for (i in 1..3) {
delay(1000)
emit(i)
}
}
// 在Android中收集数据(例如在ViewModel中)
lifecycleScope.launch {
numbersFlow.collect { value ->
Log.d("Flow", "收到: $value")
}
}
运行结果会按顺序输出1、2、3,每项间隔1秒。
与LiveData的对比
-
Flow优势:支持挂起函数、丰富的操作符链式调用(如防抖、去重)、更灵活的错误处理。适用于复杂异步场景(如网络请求、实时搜索)。
-
LiveData适用场景:轻量级数据绑定,简单生命周期感知更新。但不支持挂起函数,链式操作能力较弱。
-
选择建议:若需复杂流式处理(如实时搜索、连续网络请求),Flow更合适;若仅需简单UI数据绑定,LiveData可能更轻量。
高级特性与热流对比
冷流 vs 热流:
-
冷流(如Flow):每个收集者独立接收完整数据流,适用于网络请求、数据库查询等场景。
-
热流(如StateFlow、SharedFlow):数据生产独立于收集者,多个收集者共享同一数据源,适用于实时广播、状态共享。
-
错误处理:可通过catch操作符捕获异常,避免流中断。
热流StateFlow、SharedFlow
常见的热流有StateFlow和SharedFlow。(LiveData也是一个热流)
知道了冷流是只有接收者接受数据时,发送者才会去产生数据再发送数据给接收者。并且每个接收者都会触发完整的数据流从头开始接收完整的数据源。
而热流就是不管有没有接受者来接收数据,发送者都会生产数据,多个接受者时共享同一份数据源的,同时接受者并不会接收完整的数据源,发送者数据生产到哪了接受者就接收到哪的数据。
说的通俗一点就是:
- 冷流就像刷视频,我们开始刷这个视频这个视频才会开始播放,并且是从头开始播放
- 热流就像直播,我们不看直播这个直播也在播放,点进直播间观看也并不是从头开始看,而是只能从当前的内容开始看
冷流Demo:
bash
//每次collect都会重新发射数据
val coldFlow = flow {
println("开始生产数据")
emit(1)
emit(2)
}
// 观察者1
coldFlow.collect { println("观察者1: $it") } // 输出:1,2
// 观察者2
coldFlow.collect { println("观察者2: $it") } // 再次输出:1,2
适用场景:
- 网络请求、数据库查询等需要独立数据源的场景
- 每个订阅者需要从头消费完整的数据
热流Demo:
bash
// 创建热流(SharedFlow)
val hotFlow = MutableSharedFlow<Int>()
// 启动协程持续发射数据(即使没有订阅者)
CoroutineScope(Dispatchers.Default).launch {
repeat(4) {
delay(1000)
// 发射 0 1 2 3 4
hotFlow.emit(it)
}
}
// 观察者1(延迟1秒订阅)
CoroutineScope(Dispatchers.Main).launch {
delay(1000)
hotFlow.collect { println("观察者1: $it") } // 只能收到 1,2,3,4
}
// 观察者2(延迟5秒订阅)
CoroutineScope(Dispatchers.Main).launch {
delay(5000)
hotFlow.collect { println("观察者2: $it") } // 收不到任何数据(发射已结束)
}
适用场景:
- 需要共享实时数据的场景(如IM消息、用户定位更新)
- 数据生产是连续且独立的
总结:
| 冷流(Flow、asFlow) | 热流(StateFlow、SharedFlow) | |
|---|---|---|
| 数据产生发送时机 | 接受者收集数据时(collect) | 直接产生数据,不管有没有接受者收集 |
| 数据独立性 | 每个接受者收到的数据时独立的 | 所有接受者共享数据 |
| 数据历史 | 每个接受者从头开始获取完整数据 | 只能获取订阅后产生的数据 |
典型应用场景
-
网络请求:在ViewModel中返回Flow,Activity/Fragment中收集响应数据。
-
UI状态管理:结合Jetpack组件(如Flow Paging)处理分页数据或复杂导航状态。
-
实时功能:如搜索输入流,通过debounce操作符实现防抖。
注意事项
- 生命周期管理:在Android中需配合lifecycleScope或viewModelScope确保协程生命周期与UI一致。
- 性能优化:避免在Flow中执行阻塞操作,使用flowOn指定调度器(如Dispatchers.IO)。