协程之异步流的简单使用

115 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情

什么是异步流?

异步流,即异步返回多个计算好的值(挂起函数只返回一个值)。

流是一种类似于序列的冷流,在每次收集的时候启动。即流的发射由collect()触发。示例:

 //返回一个流,不需要挂起
 fun simple(): Flow<Int> = flow {   //流构建器
   for (i in 1..4) {
     delay(100)
     emit(i) //发射值
   }
 }
 ​
 fun main() = runBlocking {
   simple().collect {    //收集值
     value -> "simple value:$value".println()
     }
 }
  • flow{...}构建器,构建块中间的代码可以挂起
  • 返回流的函数不需要带suspend
  • 流使用 emit()发射值,使用collect()收集值
流的超时取消并停止执行
 fun simple3(): Flow<Int> = flow {   //流构建器
   for (i in 1..4) {
     "Emitting $i".println()
     delay(100)
     emit(i) //发射值
   }
 }
 ​
 fun main() = runBlocking<Unit> {
   withTimeoutOrNull(250){    //超时250ms便取消
     simple().collect { value -> " $value".println() }
   }
   "Done".println()
 }

结果: Emitting 1 1 Emitting 2 2 Emitting 3 Done

流构建器

除了使用flow{}构建流,还可以使用flowOf(vararg elements:T) 定义流集,asFlow()扩展函数可将整数区间、各种集合和序列转化为流

 flowOf("apple","pear","banner","watermelon").collect { value -> println(value) }
 (1..4).asFlow().collect { value -> " $value".println() }
 arrayOf(1.44,5.56,3.14159).asFlow().collect { value -> " $value".println() }
 arrayListOf("apple","pear","banner","watermelon").asFlow().collect { value -> " $value".println() }
流操作符
  1. 过渡流操作符应用于上游流,返回下游流。
  • filter过滤操作符:根据规则过滤上游值,结果以布尔值表示
  • map映射操作符:以上游值为参,计算返回下游值
  • transform转换操作符:可以实现filter或map,可以直接发送任意值任意次数 以获取整数区间内奇数的计算结果为例子:
(1..5).asFlow() //将整数区间转化为流
    .filter { request -> request % 2 != 0 } //过滤出奇数
    .map { request -> testFlow.performRequest(request) }  //映射出结果
    .transform { response ->    //transform 发送两次值
        emit(response)
        emit("test transform $response")
    }
    .collect { response -> println(response) } //收集流

response 1

test transform response 1

response 3

test transform response 3

response 5

test transform response 5

  1. 限长操作符take(count:Int):当流个数超过count时将抛出异常,流构建块需要通过try catch捕获异常
(1..10).asFlow().take(5).collect { value ->
    print(value)
}

12345

  1. 末端流操作符
  • collect:收集所有的值,按顺序响应每一个值;
  • toList/toSet:转化为各种集合;
  • first:获取流的第一个值;
val value = (1..10).asFlow().take(5).first()
println("value:$value")

value:1

  • single:发射单个值,如果有多个值会抛出异常;
  • reduce/fold:累加操作符,将流规约到单个值,用于所有值的链式操作,fold带一个初始值。如10的阶乘:
//创建流
val flow = (1..10).asFlow()
//计算10的阶乘,value是当前上游值,accumulator是之前的运算结果
val reduce_result = flow.reduce { accumulator, value -> accumulator * value }
//带上初始值0
val flod_result = flow.fold(0) { acc, value -> acc * value }
"reduce_result:$reduce_result".println()
"flod_result:$flod_result".println()

reduce_result:3628800

flod_result:0