emit 和 collect
如果将流的发射与接收,比做手机工厂的一条流水线,发送者是 手机的生产者,接收方则是 手机的包装者,在没有任何意外的情况下,上游每次生产好一台手机后,则应该包装好一台手机。
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,但由于已经装配好了,需要在流水线上增加一个环节,对每台手机的名字进行修改。
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成为我们的合作方,但是我们只需要选中一家,所以需要把手机和三款耳机厂商进行一个组合,看一下最终效果,由于不同包装,需要为每个耳机的配置生成一条新的流
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 ...
总结:
- 输入输出类型不同:
- map 的输入输出类型相同,都是一对一转换。
- flatMapConcat 的输入输出类型可以不同,它支持一对多的转换。
- 是否并发执行流:
- map 直接在流的每个元素上应用转换,转换 función 不会 suspend。
- flatMapConcat 中的转换 función 可以返回一个 Flow 并发执行,它支持 suspend。
- 是否合并流:
- map 只是转换每个元素,不会合并流。
- flatMapConcat 可以将多个 Flow 合并为一个 Flow。 当需要并发执行、合并流、异步转换,或者保证流顺序时,需要用 flatMapConcat。 而如果只是简单的元素转换,使用 map 更高效,且代码更简洁。
zip
最终经过内部沟通,选定了sony作为附加耳机,于是我们需要接入sony的流水线。 在接入的时候,发现一个问题,我们现在两条线,由于手机和耳机 生产速度并不相同,会造成最终的成品错乱,所以我们需要使用zip 进行产品的整合。
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
由于工厂生意火爆,加急来了一个订单,需要在规定时间内生成完毕 。
经过协商,将此事外包给两个中介公司,一组用于生成,一组用于包装,但由时间较紧凑,招来的人,工作的时间并不固定,所以需要合并搭配。
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流当前取到的值