Hello I`am Flow Welcome to Flow Unit 4
这次来聊聊,Flow 的 组合 与 完成
Flow 组合
顾名思义:就是将 flow 与 flow 组合起来执行
1 、zip 操作符
用过RxJava 的同学对 zip 一定不陌生吧
Flow 的 zip 的作用也几乎一致的
就是将 flowA 中的一个 emit 和 flowB 中对应的一个 emit 进行合并,再次做为结果传递给 终止操作!
Example
fun main() = runBlocking<Unit>{
val nums = (1..5).asFlow()
val strs = flowOf("one","two","three","four","five")
nums.zip(strs){ a,b -> "$a --- $b" }.collect{ println(it)}
}
结果打印:
1 --- one
2 --- two
3 --- three
4 --- four
5 --- five
2 、combine 操作符
与 zip 不同的点在于,combine 会将 flowA 发射的 emit 与 flowB **最新发射 **的 emit 组合起来
fun main() = runBlocking {
val flowA = (1..2).asFlow().onEach { delay(100) }
val flowB = flowOf("one","two").onEach { delay(220) }
flowA.combine(flowB) { a, b -> "$a and $b" }
.collect { println(it) }
}
结果打印:
2 and one
2 and two
//并没有 打印 “1” ,说明 flowA 发射的 “1”,完全错过了 flowB 的发射
3、flatMapConcat 操作符
将嵌套的 flow 进行 “ 打平 ”,变成 单个流 执行
private fun myMethod(i:Int) = flow{
emit("$i:First")
delay(500)
emit("$i:Second")
}
fun main() = runBlocking<Unit>{
var currentTimeMillis = System.currentTimeMillis()
(1..3).asFlow().onEach { delay(100) }
.flatMapConcat{ myMethod(it)}
.collect {println("$it at ${System.currentTimeMillis() - currentTimeMillis}") }
}
结果打印:
1:First at 125
1:Second at 629
2:First at 733
2:Second at 1236
3:First at 1341
3:Second at 1843
flow 完成
作为程序,一定会关心,它在什么时候执行完毕吧(嗯!要有SHI有ZHONG)
有两种形式
1、try-finally
这种不用多说,地球人都知道(M蛋 这也算!~)
finally:俺不是故意的
private fun myMethod() = (1..10).asFlow()
fun main() = runBlocking{
try {
myMethod().collect { println(it) }
}finally {
println("执行完了!~")
}
}
2、onCompletion 中间操作符
优点:onComletion 有一个 cause:Throwable?的可空参数
可以根据 cause 是否为空,判断程序是否出现异常,方便我们去进行下一步操作 赞!
private fun myMethod() = flow{
emit(1)
throw RuntimeException()
}
fun main() = runBlocking{
myMethod().onCompletion{
cause ->if (cause != null) println("onCompletion Exceptionally")
}
.catch{ cause -> println("catch entered $cause")}
.collect{ println(it)}
}
注意点:onCompletion 只能反应 上游出现的异常 ,不能反应 下游出现的异常
所以 应当与 try-finally 看情况使用
private fun myMethod() = (1..10).asFlow()
fun main() = runBlocking{
myMethod().onCompletion{ cause ->if (cause != null) println("onCompletion Exceptionally")}
.catch{ cause -> println("catch entered $cause")}
.collect{ value ->
check(value <= 1){
"Collected $value"
}
}
}
异常处理
也是通过 try - catch 来处理,重点是 try - catch 可以捕获 Flow 上(发射阶段)、中(中间操作)、下游(终止操作)的异常
/**
* try catch 可以捕获 Flow 三个阶段的 异常
* 1 发射阶段
* 2 中间操作阶段
* 3 终止操作阶段
*/
private fun myMethod() =
flow{
for (i in 1..3){
println("发射阶段 $i" )
emit(i)
}
}.map{
value->
check(value <= 1){
"Crash on $value"
}
"string $value"
}
fun main() = runBlocking {
try {
myMethod().collect { println(it)}
}catch (e: Throwable){
println("Caught $e")
}
}
小结:介绍了一些 Flow的 组合操作符 (zip 、combine、flatMapConcat) 完成环节(onCompletion 即注意事项)异常捕获 try catch 的作用范围