前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Kotlin 协程】Flow 操作符 ① ( 过渡操作符 | map 操作符 | transform 操作符 | 限长操作符 | take 操作符 )

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

作者头像
韩曙亮
发布2023-03-30 18:30:44
7460
发布2023-03-30 18:30:44
举报
文章被收录于专栏:韩曙亮的移动开发专栏

文章目录

一、过渡操作符


过渡操作符 相关概念 :

  • 转换流 : 使用 过渡操作符 转换 Flow 流 ;
  • 作用位置 : 过渡操作符作用 于 流的上游 , 返回 流的下游 ;
  • 非挂起函数 : 过渡操作符 不是挂起函数 , 属于冷操作符 ;
  • 运行速度 : 过渡操作符 可以 快速返回 新的 转换流 ;

1、map 操作符

通过 map 操作符 , 可以操作每个元素 , 将元素转为另外一种类型的元素 ;

map 操作符原型 :

代码语言:javascript
复制
/**
 * 返回一个流,其中包含对原始流的每个值应用给定[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 类型的元素 转为 字符串类型 元素 ;

代码语言:javascript
复制
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"
    }
}

执行结果 :

代码语言:javascript
复制
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 操作符原型 :

代码语言:javascript
复制
/**
 * 将[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)
    }
}

代码示例 :

代码语言:javascript
复制
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"
    }
}

执行结果 :

代码语言:javascript
复制
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 操作符原型 :

代码语言:javascript
复制
/**
 * 返回包含第一个[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)
        }
    }
}

代码示例 :

代码语言:javascript
复制
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}")
                        }
        }
    }
}

执行结果 :

代码语言:javascript
复制
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
在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-12-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、过渡操作符
    • 1、map 操作符
      • 2、transform 操作符
      • 二、限长操作符 ( take 操作符 )
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档