Kotlin 协程 —— Flow 过渡操作符、限长操作符

一、过渡操作符

过渡操作符用于将流中的每一个元素转换成另一个元素。

1.1. 转换:transform()

转换操作,它会调用 Flow 的 collect() 函数,然后构建一个新的 Flow,这个操作符是很多操作符的基础。

public inline fun <T, R> Flow<T>.transform(
    @BuilderInference crossinline transform: suspend FlowCollector<R>.(value: T) -> Unit
): Flow<R> = flow { // Note: safe flow is used here, because collector is exposed to transform on each operation
    collect { value ->
        // kludge, without it Unit will be returned and TCE won't kick in, KT-28938
        return@collect transform(value)
    }
} 

可以看到,transform() 函数调用了原 Flow 的 collect() 函数,然后调用传入的 lambda 表达式转换收集到的值。

如果想要继续发射值,需要重新调用 emit() 函数。

使用示例:

runBlocking {
    flowOf(1, 2, 3).transform {
        emit("transformed $it")
    }.collect {
        println("Collect: $it")
    }
} 

运行程序,输出如下:

Collect: transformed 1
Collect: transformed 2
Collect: transformed 3 

从 transform() 的源码可以看出,由于 transform() 拦截了 collect() 函数,所以 transform() 函数其实非常灵活,并不是只能用于将收集到的值转换成另一个值。我们完全可以调用多次 emit() 发射多个数据,也可以选择性的发射想要继续发射的数据。

1.2. 映射:map()

映射操作,将一个值映射为另一个值,在响应式编程中非常常见的操作。实际上就是调用了 transform() 操作符,只不过 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))
} 

使用示例:

runBlocking {
    flowOf(1, 2, 3).map {
        "mapped $it"
    }.collect {
        println("Collect: $it")
    }
} 

运行程序,输出如下:

Collect: mapped 1
Collect: mapped 2
Collect: mapped 3 

二、限长操作符

限长的意思是限制长度,用于选择 Flow 中特定的数据。

比如只取 Flow 的前几个数,或者只取后几个数。Flow 为我们内置了一些筛选条件,开发者也可以自由编写筛选条件。

2.1. 取前几个值:take()

take() 需要传入一个 count,表示取几个数。

runBlocking {
    flowOf(1, 2, 3).take(1).collect {
        println("Collect: $it")
    }
} 

运行程序,输出如下:

Collect: 1 

2.2. 取满足条件的值:takeWhile()

takeWhile() 需要传入一个 lambda 表达式,只取能够让表达式的返回值为 true 的值。需要注意的是,一旦某个值不满足条件,Flow 会立即结束。

runBlocking {
    flowOf(1, 2, 3).takeWhile {
        it % 2 == 1
    }.collect {
        println("Collect: $it")
    }
    delay(1000)
} 

这里我们在 takeWhile() 操作符中判断发射的值是否是奇数。运行程序,输出如下:

Collect: 1 

这里之所以没有输出 Collect: 3, 就是因为 takeWhile() 在遇到偶数 2 的时候,中断了整个 Flow。

2.3. 丢弃前几个值:drop()

drop() 与 take() 对应,也需要传入一个 count 值。

2.4. 丢弃满足条件的值 dropWhile()

dropWhile() 与 takeWhile() 对应,传入一个 lambda 表达式,丢弃能够让表达式的返回值为 true 的值。同样地,需要注意的是,一旦某个值不满足条件,后续的值就都不再会被丢弃。

看一个例子:

runBlocking {
    flowOf(1, 2, 1).dropWhile {
        it < 2
    }.collect {
        println("Collect $it")
    }
} 

运行程序,输出如下:

Collect 2
Collect 1 

这里输出了最后一个值:Collect 1,原因就是 2 已经不满足 it < 2 这个条件了,drop 的工作到 2 就结束了,最后一个 1 不会再被丢弃。

三、小结

本文我们介绍了 Flow 的过渡操作符 transform()、map(),限长操作符 take()、takeWhile()、drop()、dropWhile()。值得注意的是 takeWhile()、dropWhile() 会在条件不满足后立即退出判断,并不是每个值都会被判断。

文末

Kotlin 是一种新型的静态类型编程语言,有超过 60% 的专业 Android 开发者在使用,它有助于提高工作效率、开发者满意度和代码安全性。不仅可以减少常见代码错误,还可以轻松集成到现有应用中。

在这里为了方便大家系统的学习Kotlin,这里特意联合了阿里P7架构师和谷歌技术团队共同整理了一份Kotlin全家桶学习资料(扫码免费领取~

高级Kotlin强化实战

第一章 Kotlin入门教程

  • Kotlin 概述
  • Kotlin 与 Java 比较
  • 巧用 Android Studio
  • 认识 Kotlin 基本类型
  • 走进 Kotlin 的数组
  • 走进 Kotlin 的集合
  • 集合问题
  • 完整代码
  • 基础语法

在这里插入图片描述

第二章 Kotlin 实战避坑指南

  • 方法入参是常量,不可修改
  • 不要 Companion 、INSTANCE ?
  • Java 重载,在 Kotlin 中怎么巧妙过渡一下?
  • Kotlin 中的判空姿势
  • Kotlin 复写 Java 父类中的方法
  • Kotlin “狠”起来,连TODO 都不放过!
  • is、as` 中的坑
  • Kotlin 中的 Property 的理解
  • also 关键字
  • takeIf 关键字
  • takeIf 关键字
  • 单例模式的写法

在这里插入图片描述

第三章 项目实战《Kotlin Jetpack 实战》

  • 从一个膜拜大神的 Demo 开始
  • Kotlin 写 Gradle 脚本是一种什么体验?
  • Kotlin 编程的三重境界
  • Kotlin 高阶函数
  • Kotlin 泛型
  • Kotlin 扩展
  • Kotlin 委托
  • 协程“不为人知”的调试技巧
  • 图解协程:suspend

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值