Flow 操作符(一) 转换、合并

99 阅读3分钟

emit 和 collect

如果将流的发射与接收,比做手机工厂的一条流水线,发送者是 手机的生产者,接收方则是 手机的包装者,在没有任何意外的情况下,上游每次生产好一台手机后,则应该包装好一台手机。 图片.png

    flow {
        for (i in 1..3) {
            println("produce phone $i")
            emit(Phone(i))
        }
    }.collect {
        println("package phone $it")
    }
data class Phone(val id: Int, var name:String = "XM")
//produce phone 1
//package phone 1
//produce phone 2
//package phone 2
//produce phone 3
//package phone 3

map

没有意外就是最大的意外,接到厂里需求,隔壁厂手机型号已经到了Banana 15 Pro Max,但由于已经装配好了,需要在流水线上增加一个环节,对每台手机的名字进行修改。

图片.png

flow {
    for (i in 1..3) {
        println("produce $i phone  ")
        emit(Phone(i))
    }
}.map {
    it.copy(name = "XM-X")
}.collect {
    println("package $it complete ... ")
}
//produce 1 phone
//package Phone(id=1, name=XM-X) complete ...
//produce 2 phone
//package Phone(id=2, name=XM-X) complete ...
//produce 3 phone
//package Phone(id=3, name=XM-X) complete ...

flatMapConcat(原flatMap)

由于竞争对手对产品增配,现在每台手机要赠送一个耳机作为配件,经过洽谈,选中几家厂商,AirPods,AKG,Sony成为我们的合作方,但是我们只需要选中一家,所以需要把手机和三款耳机厂商进行一个组合,看一下最终效果,由于不同包装,需要为每个耳机的配置生成一条新的流 图片.png

flow {
    for (i in 1..3) {
        println("produce $i phone  ")
        emit(Phone(i))
    }
}.flatMapConcat {
    flowAkg(it)
}.collect {
    println("package $it complete ... ")
}
produce 1 phone  
package Phone(id=1, name=XM, parts=Parts(headset=Akg)) complete ... 
package Phone(id=1, name=XM, parts=Parts(headset=Airpods)) complete ... 
package Phone(id=1, name=XM, parts=Parts(headset=Sony)) complete ... 
...
produce 3 phone  
package Phone(id=3, name=XM, parts=Parts(headset=Akg)) complete ... 
package Phone(id=3, name=XM, parts=Parts(headset=Airpods)) complete ... 
package Phone(id=3, name=XM, parts=Parts(headset=Sony)) complete ... 

总结:

  1. 输入输出类型不同:
  • map 的输入输出类型相同,都是一对一转换。
  • flatMapConcat 的输入输出类型可以不同,它支持一对多的转换。
  1. 是否并发执行流:
  • map 直接在流的每个元素上应用转换,转换 función 不会 suspend。
  • flatMapConcat 中的转换 función 可以返回一个 Flow 并发执行,它支持 suspend。
  1. 是否合并流:
  • map 只是转换每个元素,不会合并流。
  • flatMapConcat 可以将多个 Flow 合并为一个 Flow。 当需要并发执行、合并流、异步转换,或者保证流顺序时,需要用 flatMapConcat。 而如果只是简单的元素转换,使用 map 更高效,且代码更简洁。

zip

最终经过内部沟通,选定了sony作为附加耳机,于是我们需要接入sony的流水线。 在接入的时候,发现一个问题,我们现在两条线,由于手机和耳机 生产速度并不相同,会造成最终的成品错乱,所以我们需要使用zip 进行产品的整合。

图片.png

val headsetFlow = flow {
    for (i in 1..3) {
        delay(1000)
        println("produce Sony headset $i time ${System.currentTimeMillis() / 1000}")
        emit("Sony $i")
    }
}
flow {
    for (i in 1..3) {
        delay(3000)
        println("produce  phone  $i time ${System.currentTimeMillis() / 1000}")
        emit(Phone(i))
    }
}.zip(headsetFlow) { phone, headset ->
    println("zip  phone and headset time ${System.currentTimeMillis() / 1000}")
    phone.copy(parts = Parts(headset = headset))
}.collect {
    println("package $it complete ... ")
}
//produce Sony headset 1 time 1692687263
//produce  phone  1 time 1692687265
//zip  phone and headset time 1692687265
//package Phone(id=1, name=XM, parts=Parts(headset=Sony 1)) complete ...
//produce Sony headset 2 time 1692687266
//produce  phone  2 time 1692687268
//zip  phone and headset time 1692687268
//package Phone(id=2, name=XM, parts=Parts(headset=Sony 2)) complete ...
//produce Sony headset 3 time 1692687269
//produce  phone  3 time 1692687271
//zip  phone and headset time 1692687271
//package Phone(id=3, name=XM, parts=Parts(headset=Sony 3)) complete ...

总结:
如果两个流发送数据有时间差,会进行等待,向后兼容
如果两个流的数据有差异,会进行像小兼容

combine

由于工厂生意火爆,加急来了一个订单,需要在规定时间内生成完毕 。
经过协商,将此事外包给两个中介公司,一组用于生成,一组用于包装,但由时间较紧凑,招来的人,工作的时间并不固定,所以需要合并搭配。

图片.png

val teamFlow = flow {
    for (i in 1..4) {
        delay(1000)
        emit("Team1 Person $i")
    }
}
val team2Flow = flow {
    for (i in 1..4) {
        delay(1500)
        emit("Team2 Person $i")
    }
}
combine(teamFlow, team2Flow) { team1, team2 ->
    "$team1 combine $team2"
}.collect {
    println("Person Group $it time ${System.currentTimeMillis() / 1000}")
}
//Person Group Team1 Person 1 combine Team2 Person 1 time 1692694741
//Person Group Team1 Person 2 combine Team2 Person 1 time 1692694741
//Person Group Team1 Person 2 combine Team2 Person 2 time 1692694742
//Person Group Team1 Person 3 combine Team2 Person 2 time 1692694742
//Person Group Team1 Person 4 combine Team2 Person 2 time 1692694743
//Person Group Team1 Person 4 combine Team2 Person 3 time 1692694744
//Person Group Team1 Person 4 combine Team2 Person 4 time 1692694745

总结:
combine可以多个flow进行合并 combine不在乎时间差异和流的大小差异 A流当前取到的值+B流当前取到的值

参考资料