Kotlin 协程Flow 操作符 ① ( 过渡操作符 | map 操作符 | transform 操作符 | 限长操作符 | take 操作符 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin 协程Flow 操作符 ① ( 过渡操作符 | map 操作符 | transform 操作符 | 限长操作符 | take 操作符 )相关的知识,希望对你有一定的参考价值。
文章目录
一、过渡操作符
过渡操作符 相关概念 :
- 转换流 : 使用 过渡操作符 转换 Flow 流 ;
- 作用位置 : 过渡操作符作用 于 流的上游 , 返回 流的下游 ;
- 非挂起函数 : 过渡操作符 不是挂起函数 , 属于冷操作符 ;
- 运行速度 : 过渡操作符 可以 快速返回 新的 转换流 ;
1、map 操作符
通过 map 操作符 , 可以操作每个元素 , 将元素转为另外一种类型的元素 ;
map 操作符原型 :
/**
* 返回一个流,其中包含对原始流的每个值应用给定[transform]函数的结果。
*/
public inline fun <T, R> Flow<T>.map(crossinline transform: suspend (value: T) -> R): Flow<R> = transform value ->
return@transform emit(transform(value))
代码示例 : 将 Flow 中发射的 Int 元素 转为 字符串 ; 通过 map 操作符 , 将 Int 类型的元素 转为 字符串类型 元素 ;
package kim.hsl.coroutine
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
class MainActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runBlocking
(0..3).asFlow()
// 通过 map 操作符将 Int 转为字符串元素
.map
stringConvert(it)
.collect
println("collect : $it")
// 将 Int 转为 字符串
suspend fun stringConvert(num: Int): String
delay(1000)
return "convert $num"
执行结果 :
2022-12-26 11:28:07.370 23972-23972/kim.hsl.coroutine I/System.out: collect : convert 0
2022-12-26 11:28:08.371 23972-23972/kim.hsl.coroutine I/System.out: collect : convert 1
2022-12-26 11:28:09.412 23972-23972/kim.hsl.coroutine I/System.out: collect : convert 2
2022-12-26 11:28:10.452 23972-23972/kim.hsl.coroutine I/System.out: collect : convert 3
2、transform 操作符
通过 transform 操作符 , 可以操作每个元素 , 可以在单个元素处理时 , 发射多次元素 ;
transform 操作符原型 :
/**
* 将[transform]函数应用到给定流的每个值。
*
* ' transform '的接收者是[FlowCollector],因此' transform '是一个
* 灵活的函数,可以转换发出的元素,跳过它或多次发出它。
*
* 该操作符泛化了[filter]和[map]操作符和
* 可以用作其他操作符的构建块,例如:
*
* ```
* fun Flow<Int>.skipOddAndDuplicateEven(): Flow<Int> = transform value ->
* if (value % 2 == 0) // Emit only even values, but twice
* emit(value)
* emit(value)
* // Do nothing if odd
*
* ```
*/
public inline fun <T, R> Flow<T>.transform(
@BuilderInference crossinline transform: suspend FlowCollector<R>.(value: T) -> Unit
): Flow<R> = flow // 注意:这里使用的是安全流,因为收集器对每个操作的转换都是公开的
collect value ->
// 没有它,单元将被退回,TCE将不会生效,KT-28938
return@collect transform(value)
代码示例 :
package kim.hsl.coroutine
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
class MainActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runBlocking
(0..3).asFlow()
.transform it ->
// 在 transform 操作符中发射 2 个元素
emit(it)
emit(stringConvert(it))
.collect
println("collect : $it")
// 将 Int 转为 字符串
suspend fun stringConvert(num: Int): String
delay(1000)
return "convert $num"
执行结果 :
2022-12-26 11:38:14.091 25902-25902/kim.hsl.coroutine I/System.out: 接收元素 : 0
2022-12-26 11:38:14.091 25902-25902/kim.hsl.coroutine I/System.out: 发射元素 : 0
2022-12-26 11:38:15.146 25902-25902/kim.hsl.coroutine I/System.out: 接收元素 : convert 0
2022-12-26 11:38:16.189 25902-25902/kim.hsl.coroutine I/System.out: 发射元素 : convert 0
2022-12-26 11:38:16.189 25902-25902/kim.hsl.coroutine I/System.out: 接收元素 : 1
2022-12-26 11:38:16.189 25902-25902/kim.hsl.coroutine I/System.out: 发射元素 : 1
2022-12-26 11:38:17.229 25902-25902/kim.hsl.coroutine I/System.out: 接收元素 : convert 1
2022-12-26 11:38:18.269 25902-25902/kim.hsl.coroutine I/System.out: 发射元素 : convert 1
2022-12-26 11:38:18.270 25902-25902/kim.hsl.coroutine I/System.out: 接收元素 : 2
2022-12-26 11:38:18.270 25902-25902/kim.hsl.coroutine I/System.out: 发射元素 : 2
2022-12-26 11:38:19.309 25902-25902/kim.hsl.coroutine I/System.out: 接收元素 : convert 2
2022-12-26 11:38:20.349 25902-25902/kim.hsl.coroutine I/System.out: 发射元素 : convert 2
2022-12-26 11:38:20.349 25902-25902/kim.hsl.coroutine I/System.out: 接收元素 : 3
2022-12-26 11:38:20.349 25902-25902/kim.hsl.coroutine I/System.out: 发射元素 : 3
2022-12-26 11:38:21.389 25902-25902/kim.hsl.coroutine I/System.out: 接收元素 : convert 3
2022-12-26 11:38:22.429 25902-25902/kim.hsl.coroutine I/System.out: 发射元素 : convert 3
二、限长操作符 ( take 操作符 )
通过 take 操作符 , 可以选择选取指定个数的发射元素 ;
如 : 在 Flow 流中发射了 4 个元素 , 但是调用了 Flow#take(2) , 只收集其中 2 个元素 ;
take 操作符原型 :
/**
* 返回包含第一个[count]元素的流。
* 当[count]元素被消耗时,原始流将被取消。
* 如果[count]不是正数,抛出[IllegalArgumentException]。
*/
public fun <T> Flow<T>.take(count: Int): Flow<T>
require(count > 0) "Requested element count $count should be positive"
return unsafeFlow
var consumed = 0
try
collect value ->
// 注意:这个for take不是故意用collectWhile写的。
// 它首先检查条件,然后对emit或emitAbort进行尾部调用。
// 这样,正常的执行不需要状态机,只需要终止(emitAbort)。
// 有关不同方法的比较,请参阅“TakeBenchmark”。
if (++consumed < count)
return@collect emit(value)
else
return@collect emitAbort(value)
catch (e: AbortFlowException)
e.checkOwnership(owner = this)
代码示例 :
package kim.hsl.coroutine
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
class MainActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runBlocking
(0..3).asFlow()
.take(2)
.collect
println("接收元素 : $it")
执行结果 :
2022-12-26 11:42:25.560 27701-27701/kim.hsl.coroutine I/System.out: 接收元素 : 0
2022-12-26 11:42:25.560 27701-27701/kim.hsl.coroutine I/System.out: 接收元素 : 1
以上是关于Kotlin 协程Flow 操作符 ① ( 过渡操作符 | map 操作符 | transform 操作符 | 限长操作符 | take 操作符 )的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin 协程Flow 流异常处理 ( 收集元素异常处理 | 使用 try...catch 代码块捕获处理异常 | 发射元素时异常处理 | 使用 Flow#catch 函数捕获处理异常 )
Kotlin 协程Flow 流异常处理 ( 收集元素异常处理 | 使用 try...catch 代码块捕获处理异常 | 发射元素时异常处理 | 使用 Flow#catch 函数捕获处理异常 )
Kotlin 协程Flow 异步流 ① ( 以异步返回返回多个返回值 | 同步调用返回多个值的弊端 | 尝试在 sequence 中调用挂起函数返回多个返回值 | 协程中调用挂起函数返回集合 )
Kotlin 协程Flow 异步流 ① ( 以异步返回返回多个返回值 | 同步调用返回多个值的弊端 | 尝试在 sequence 中调用挂起函数返回多个返回值 | 协程中调用挂起函数返回集合 )