【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

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值