如何将两个Flow组合为带空值的键对,是否有类似zip的扩展函数
实现方案说明
现有函数适配性判断
kotlinx.coroutines 标准库中不存在完全匹配该需求的现成Flow扩展函数,常用组合函数的特性和需求差异如下:
zip:必须两个流各发射一个新值才会生成一次组合结果,既无法响应同一个A值对应的多次B值更新,也不会在A更新时立刻发射带空值的配对combine:任意流发射新值时都会取两个流的最新值组合,但无法区分B值是在A更新前还是更新后发射的,也不会自动将B值重置为空
自定义实现代码
可以通过combineTransform自定义扩展函数实现需求,代码如下:
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.distinctUntilChanged fun <A, B> Flow<A>.combineWithNewBOnly(other: Flow<B>): Flow<Pair<A, B?>> { // 记录上一次发射的A值 var lastA: A? = null // 标记当前A值发射后,B是否有发射过新值 var hasNewBAfterAUpdate = false // 记录最新的B值 var latestB: B? = null return combineTransform(this, other) { newA, newB -> // 判断A是否为新发射的值 if (newA != lastA) { lastA = newA // A更新后重置B的有效标记 hasNewBAfterAUpdate = false // 立刻发射A和空值的配对 emit(newA to null) } // 判断B是否为新发射的值 if (newB != latestB) { latestB = newB hasNewBAfterAUpdate = true } // B有更新的情况下发射A和最新B的配对 if (hasNewBAfterAUpdate) { emit(newA to newB) } }.distinctUntilChanged() // 可选,避免相同配对重复发射 }
逻辑说明
该实现完全匹配你给出的示例效果:
- 每次Flow A发射新值时,立刻发射
(新A值, null)的配对,同时清空之前B值的有效性标记 - 只有在当前A值发射之后,Flow B发射的新值才会被标记为有效
- 同一A值的生命周期内,Flow B每发射一次新值,就会生成一次
(当前A值, 新B值)的配对 - 末尾的
distinctUntilChanged()可根据业务需求决定是否保留,作用是过滤掉完全相同的重复配对结果
注意:如果你的业务场景中Flow A可能发射完全相同的重复值,且要求即使值相同只要是新发射的事件就重置B的状态,可将A的元素包裹为带自增版本号的数据类,通过版本号判断是否为新发射的A值,而不是通过值相等判断。
内容的提问来源于stack exchange,提问作者Cilenco
相关产品推荐
相关产品推荐

