Android Flow 零基础到入门教程———操作符详解!

610 阅读3分钟

Android Flow 操作符详解

一、操作符分类

  1. 中间操作符:对流进行转换处理
  2. 终端操作符:触发流的执行
  3. 异常处理符:处理流中的异常
  4. 组合操作符:多个流的组合操作

二、常用中间操作符

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)
    }

八、操作符使用建议

  1. 链式调用顺序map/filter 等轻量操作在前,耗时操作在后
  2. 线程切换:使用 flowOn 控制操作符执行上下文
flow { /* 生产数据 */ }
  .map { ... }        // 在 IO 线程
  .flowOn(Dispatchers.IO)
  .filter { ... }     // 在默认线程
  1. 避免阻塞:在操作符中使用 delay 代替 Thread.sleep
  2. 及时取消:使用 viewModelScope 或 lifecycleScope 管理协程

九、常用操作符速查表

操作符作用描述
map数据转换
filter数据过滤
onEach对每个值执行副作用操作
take取前N个值
drop跳过前N个值
scan累加器操作
flatMapMerge并发展开流
distinctUntilChanged去重连续相同值

通过灵活组合这些操作符,可以实现复杂的异步数据流处理逻辑。建议在实际开发中根据具体需求选择合适的操作符组合,并注意操作符的执行顺序对性能的影响。

更多分享

  1. Android Flow 零基础到入门教程———基本概念和使用
  2. Android Flow + ViewModel 最佳实践教程
  3. 一文吃透Kotlin中冷流(Clod Flow)和热流(Hot Flow)