Android Flow 操作符详解
一、操作符分类
- 中间操作符:对流进行转换处理
- 终端操作符:触发流的执行
- 异常处理符:处理流中的异常
- 组合操作符:多个流的组合操作
二、常用中间操作符
1. map - 数据转换
fun mapExample(): Flow<String> = flow {
emit(1)
emit(2)
emit(3)
}.map {
"Number $it" // 转换为字符串
}
// 输出:Number 1, Number 2, Number 3
2. filter - 数据过滤
fun filterExample(): Flow<Int> = flow {
(1..10).forEach { emit(it) }
}.filter {
it % 2 == 0 // 只保留偶数
}
// 输出:2,4,6,8,10
3. transform - 复杂转换
fun transformExample(): Flow<String> = flow {
emit("A")
emit("B")
}.transform { value ->
if (value == "A") {
emit("Apple")
}
emit("${value}2")
}
// 输出:Apple, A2, B2
4. debounce - 防抖处理
// 适用于搜索框输入场景
fun searchFlow(): Flow<String> = callbackFlow {
val callback = object : SearchCallback {
override fun onQueryChanged(query: String) {
trySend(query)
}
}
registerCallback(callback)
awaitClose { unregisterCallback(callback) }
}.debounce(300) // 300毫秒内只接收最新值
三、终端操作符
1. collect - 基础收集
lifecycleScope.launch {
flow.collect { value ->
// 处理每个值
}
}
2. launchIn - 在指定协程作用域启动
flow
.onEach { updateUI(it) }
.launchIn(viewModelScope) // 自动管理生命周期
3. toList/toSet - 转换为集合
val numbers = flow {
emit(1)
emit(2)
}.toList() // 结果:[1, 2]
四、组合操作符
1. zip - 组合两个流
val flow1 = flowOf("A", "B", "C")
val flow2 = flowOf(1, 2, 3)
flow1.zip(flow2) { a, b ->
"$a$b"
}.collect {
// 输出:A1, B2, C3
}
2. combine - 动态组合
val countFlow = flowOf(1, 2, 3)
val nameFlow = flowOf("Apple", "Banana")
countFlow.combine(nameFlow) { count, name ->
"$count $name"
}.collect {
// 输出:1 Apple, 2 Apple, 2 Banana, 3 Banana
}
五、异常处理操作符
1. catch - 捕获异常
flow {
emit(1)
throw RuntimeException("Error")
}.catch { e ->
// 捕获上游异常
emit(-1)
}.collect {
// 输出:1, -1
}
2. retry - 重试机制
flow {
// 模拟可能失败的操作
if (Random.nextBoolean()) throw IOException()
emit("Success")
}.retry(3) { cause ->
cause is IOException // 仅针对特定异常重试
}
六、高级操作符
1. buffer - 缓冲处理
flow {
repeat(3) {
delay(100)
emit(it)
}
}.buffer() // 生产消费解耦
.collect {
delay(300)
println(it)
}
2. flatMapConcat - 顺序展开
fun getUserId(): Flow<Int> = flow { emit(1) }
getUserId()
.flatMapConcat { id ->
getUserDetail(id) // 返回Flow<User>
}
.collect { user ->
// 依次处理每个用户
}
七、操作符组合示例
// 模拟搜索建议功能
searchQueryFlow
.debounce(300)
.filter { it.length > 2 }
.distinctUntilChanged()
.mapLatest { query ->
api.searchSuggestions(query)
}
.catch { e ->
emit(emptyList())
}
.collect { suggestions ->
updateSuggestions(suggestions)
}
八、操作符使用建议
- 链式调用顺序:
map/filter等轻量操作在前,耗时操作在后 - 线程切换:使用
flowOn控制操作符执行上下文
flow { /* 生产数据 */ }
.map { ... } // 在 IO 线程
.flowOn(Dispatchers.IO)
.filter { ... } // 在默认线程
- 避免阻塞:在操作符中使用
delay代替Thread.sleep - 及时取消:使用
viewModelScope或lifecycleScope管理协程
九、常用操作符速查表
| 操作符 | 作用描述 |
|---|---|
map | 数据转换 |
filter | 数据过滤 |
onEach | 对每个值执行副作用操作 |
take | 取前N个值 |
drop | 跳过前N个值 |
scan | 累加器操作 |
flatMapMerge | 并发展开流 |
distinctUntilChanged | 去重连续相同值 |
通过灵活组合这些操作符,可以实现复杂的异步数据流处理逻辑。建议在实际开发中根据具体需求选择合适的操作符组合,并注意操作符的执行顺序对性能的影响。