0
点赞
收藏
分享

微信扫一扫

【Kotlin 协程】Flow 操作符 ① ( 过渡操作符 | map 操作符 | transform 操作符 | 限长操作符 | take 操作符 )


文章目录

  • ​​一、过渡操作符​​
  • ​​1、map 操作符​​
  • ​​2、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

【Kotlin 协程】Flow 操作符 ① ( 过渡操作符 | map 操作符 | transform 操作符 | 限长操作符 | take 操作符 )_Flow操作符



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

【Kotlin 协程】Flow 操作符 ① ( 过渡操作符 | map 操作符 | transform 操作符 | 限长操作符 | take 操作符 )_Flow操作符_02






二、限长操作符 ( 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 操作符 )_Flow_03


举报

相关推荐

0 条评论