如何合并Kotlin Flow?实现Foo ID或内部状态变更监听的方案咨询
问题描述
现有以下两个挂起函数:
// 返回整数流,每个整数对应Foo的唯一ID // 当前Foo变化时会发射新的整数 suspend fun getCurrentFooId(): Flow<Int>
// 返回Foo对象流 // 当最后一个Foo的内部状态变化时,会发射新的Foo实例 suspend fun getFooForId(fooId: Int): Flow<Foo>
需求:需要一个Flow<Foo>,当当前Foo的ID发生变化或者当前Foo的内部状态发生变化时,发射新的Foo实例。
限制:无法直接合并这两个流,因为必须先收集第一个流获取Foo ID后,才能调用getFooForId()方法。
疑问:应该使用channel flow来并发合并它们,还是有更优的实现方式?
最优实现方式
完全没必要用Channel Flow,直接用Kotlin Flow的flatMapLatest操作符就能搞定,这是最简洁、最贴合你场景的方案。
实现代码
fun getCurrentFoo(): Flow<Foo> { return getCurrentFooId() .flatMapLatest { fooId -> getFooForId(fooId) } }
原理说明
flatMapLatest的逻辑很直接:每当上游的getCurrentFooId()发射新ID时,会立刻取消之前正在收集的旧Foo流,转而订阅新ID对应的Foo流。- 这样一来,不管是Foo的ID切换导致换了新对象,还是当前Foo的内部状态更新,这个流都会及时发射最新的Foo实例,完全满足你的需求。
- 对比Channel Flow,这种写法不需要手动处理并发、通道这些细节,Flow框架已经帮你封装好了订阅切换、自动取消的逻辑,代码更简洁,也不容易写出bug。
为什么不用Channel Flow?
Channel Flow一般用来处理更复杂的并发场景,比如需要手动控制发射时机、合并多个无依赖的流,或者要在流里执行阻塞操作的时候。而你的场景中两个流有明确的依赖关系——必须先拿到ID才能获取对应的Foo流,flatMapLatest就是专门为这种"上游触发下游订阅"的场景设计的,用它才是最顺手的选择。
内容的提问来源于stack exchange,提问作者Barry Fruitman
相关产品推荐
相关产品推荐

