Kotlin Flow 操作符

news2025/1/21 11:25:05

前言

Kotlin 拥有函数式编程的能力,使用Kotlin开发,可以简化开发代码,层次清晰,利于阅读。

然而Kotlin拥有操作符很多,其中就包括了flow。Kotlin Flow 如此受欢迎大部分归功于其丰富、简洁的操作符,巧妙使用Flow操作符可以大大简化我们的程序结构,提升可读性与可维护性。本篇文章列举一些比较常用 Kotlin 操作符,通过关键原理与使用场景列子来讲解Flow操作符。

1. collect接收操作符

用于数据接收,此操作符没有返回对象,后面不可再添加操作符:


fun flowCollect() {
//流启动
        viewModelScope.launch {
            flow {
                for (i in 1..3) {
                    Log.d("TAG"," flowCollect $i")
                    emit(i)
                    delay(1000)
                }
            }.collect {
                Log.d("TAG"," collect $it")
            }//后面不可再接收其他操作符
        }
    }

2. launchIn操作符

流的启动主要有两种,一种是上面的作用域.launch启动一个流,用collect操作符接收数据;

一种是launchIn操作符启动流,官方不建议用这种,可能出于数据安全考虑,一般建议在onResume方法调用后启动协程,因为怕数据接收了,但View还没创建出来。但链式调用真的很好用,用onEach操作符接收数据。


 flow {
            for (i in 1..3) {
                Log.d("TAG"," flowCollect $i")
                emit(i)
                delay(1000)
            }
        }.onCompletion {
            Log.d("TAG","onCompletion ")
        }.launchIn(viewModelScope)//在ViewModel中,直接launchIn在ViewModelScope作用域

3. onEach操作符

返回一个流,该流在上游流的每个值向下游发出之前调用给定的操作。也可以用来接收数据,与上面collect不同的是此操作符返回流,我们后面还可接其他操作符。上面的launchIn操作符启动时,可用于接收数据。

 fun flowOnEach() {
        flow {
            for (i in 1..3) {
                LogUtils.d("Emitting $i")
                emit(i)
                delay(1000)
            }
        }.onEach {
            LogUtils.d("onEach $it")
        }.onCompletion {
            LogUtils.d("onCompletion ")
        }.launchIn(viewModelScope)
    }

4. reduce操作符

reduce 操作符可以将所有数据累加(加减乘除)得到一个结果,如下所示:
在这里插入图片描述

    fun testReduce(){
        val result = listOf(1, 2, 3).reduce { a, b ->
            a + b
        }
        print("list reduce result:$result")
    }

查看测试结果输出如下:
在这里插入图片描述

注意⚠️:
1: 如果 flow 中没有数据,将抛出异常。如不希望抛异常,可使用 reduceOrNull 方法。
2: reduce 操作符不能变换数据类型。比如,Int 集合的结果不能转换成 String 结果。

5. fold操作符

fold 和 reduce 很类似,但是 fold 可以变换数据类型
在这里插入图片描述

有时候,我们不需要一个结果值,而是需要继续操 flow,可使用 runningFold :

flowOf(1, 2, 3).runningFold("a") { a, b ->
    a + b
}.collect {
    println(it)
}

查看输出结果:

a
a1
a12
a123

同样的,reduce 也有类似的方法 runningReduce:

flowOf(1, 2, 3).runningReduce { a, b ->
    a + b
}.collect {
    println(it)
}

查看输出结果:

1
3
6

6. debounce操作符

debounce 需要传递一个毫秒值参数,功能是:只有达到指定时间后才发出数据,最后一个数据一定会发出。
在这里插入图片描述

例如,定义 1000 毫秒,也就是 1 秒,被观察者发出数据,1秒后,观察者收到数据,如果 1 秒内多次发出数据,则重置计算时间。

flow {
    emit(1)
    delay(500)
    emit(2)
    delay(550)
    emit(3)
    delay(1000)
    emit(4)
    delay(1010)
}.debounce(
    1000
).collect {
    println(it)
}

查看输出结果,只有休眠1000和1010符合要求:

3
4

所以,rebounce 的应用场景是限流功能。

7. sample操作符

sample 和 debounce 很像,区别是:在规定时间内,只发送一个数据:
在这里插入图片描述

flow {
    repeat(4) {
        emit(it)
        delay(50)
    }
}.sample(100).collect {
    println(it)
}

输出结果:

1
3

所以,sample 的应用场景是截流功能。

8. flatmapMerge操作符

简单的说就是获得两个 flow 的乘积或全排列,合并并且平铺,发出一个 flow。
在这里插入图片描述

flowOf(1, 3).flatMapMerge {
    flowOf("$it a", "$it b")
}.collect {
    println(it)
}

输出结果:

1 a
1 b
3 a
3 b

注意⚠️:flatmapMerge 还有一个特性,flatmapMerge 可以设置并发量,可以理解为 flatmapMerge 是线程安全的,而 flatmapConcat 不是线程安全的。会在下一个操作符里提及。

9. flatmapConcat操作符

举个列子:

flowOf(1, 3).flatMapConcat {
    flowOf("a", "b", "c")
}.collect {
    println(it)
}

在这里插入图片描述

功能和 flatmapMerge 一致,不同的是 flatmapMerge 可以设置并发量,可以理解为 flatmapMerge 是线程安全的,而 flatmapConcat 不是线程安全的。

本质上,在 flatmapMerge 的并发参数设置为 1 时,和 flatmapConcat 基本一致,而并发参数大于 1 时,采用 channel 的方式发出数据,具体内容请参阅源码。

10. buffer操作符

介绍 buffer 的时候,先要看这样一段代码:

flowOf("A", "B", "C", "D")
.onEach {
    println("1 $it")
}
.collect { println("2 $it") }

我们注意查看一下输出结果:

1 A
2 A
1 B
2 B
1 C
2 C
1 D
2 D

如果我们加上 buffer 的代码:

flowOf("A", "B", "C", "D")
.onEach {
    println("1 $it")
}
.buffer()
.collect { println("2 $it") }

在查看一下加上 buffer 的代码的输出结果:

1 A
1 B
1 C
1 D
2 A
2 B
2 C
2 D

对比俩次输出结果,会发现输出内容有所不同,buffer 操作符可以改变收发顺序,像有一个容器作为缓冲似的,在容器满了或结束时,下游开始接到数据,onEach 添加延迟,效果更明显。

11 combine操作符

合并两个 flow,长的一方会持续接受到短的一方的最后一个数据,直到结束:

flowOf(1, 3).combine(
    flowOf("a", "b", "c")
) { a, b -> b + a }
.collect {
    println(it)
}

查看输出结果如下:

a1
b3
c3

12. zip操作符

也是合并两个 flow,结果长度与短的 flow 一致,很像木桶原理。

    fun testZip() {
        runBlocking {
            val time = measureTimeMillis {
                val flow1 = flow { emit("a") emit ("b") emit ("c") emit ("d") }
                val flow2 = flow { emit("1") emit ("2") } flow1 . zip (flow2) { sex, subject -> "$sex-->$subject" }.collect { println(it) }
            } println ("use time:$time")
        }
    }

查看输出结果:

a-->1
b-->2
use time:71

通过输出可以看出flow2先结束了,并且flow1没发送完成。
zip原理简单来说:
在这里插入图片描述
可以看出,zip的特点:

短的Flow结束,另一个Flow也结束。

13. flatMapLatest操作符

与 collectLatest 操作符类似,处理最新值,也有相对应的“最新”展平模式,在发出新流后立即取消先前流的收集。 这由 flatMapLatest 操作符来实现。

14. distinctUntilChanged操作符

和前一个数据不同,才能收到,和前一个数据相同,则会被过滤掉。
在这里插入图片描述

flowOf(1, 1, 2, 2, 3, 1).distinctUntilChanged().collect {
    println(it)
}

运行查看输出结果:

1
2
3
1

总结

Kotlin 拥有函数式编程的能力,同时Kotlin拥有很多操作符,其中就包括了flow。合理使用Kotlin操作符可以使我们的代码更加简化,层次清晰,利于阅读。因此,要灵活使用Kotlin操作符。

参考:

  1. 协程文档
  2. 协程中文网
  3. 这一次,让Kotlin Flow 操作符真正好用起来
  4. Kotlin 协程Flow主要操作符(一)
  5. Kotlin 协程Flow主要操作符(二)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1290295.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

top K问题(C语言)

目录 前言 top K问题 模拟数据 建堆 验证(简单了解即可) 最终代码 调试部分 前言 在大小堆的实现(C语言)中我们讨论了堆的实际意义,在看了就会的堆排序(C语言)中我们完成了堆排序&#…

MYSQL全语法速查(含示例)

文章目录 1.从简单的查询开始查找所有记录(SELECT *)查找记录中的所有登录名(SELECT)查找登录名为admin的密码(WHERE)查找电话号码非空的记录(IS NOT NULL)查找所在城市为北京或者用户名字是李四的记录(OR)查找所在城市为北京并且用户名字是张三的记录(AND)查找用户名字是李四或…

6个实用又好用的交互原型工具!

在 UI/UX 设计中,原型设计是至关重要的一步。正如用户体验中的其它环节一样,有无数的交互原型工具可以帮助你完成原型设计。市场上有太多的交互原型工具,如果你不知道选择哪一种,那么我们将为你介绍 6 个实用又好用的交互原型工具…

C++ day56 两个字符串的删除操作 编辑距离

题目1:583 两个字符串的删除操作 题目链接:两个字符串的删除操作 对题目的理解 返回使两个单词word1和word2相同的最少删除多少个元素,两个单词至少包含一个字母,且仅包含小写字母 思路1:这道题与昨天的不同子序列…

Dagger2使用

在android引入Dagger2库 //引入Dagger2implementation("com.google.dagger:dagger:2.48.1")annotationProcessor ("com.google.dagger:dagger-compiler:2.48.1") 构造器注入 创建一个类 public class Car {//在构造器上面添加dagger的Inject即可Injectp…

现代雷达车载应用——第2章 汽车雷达系统原理 2.1节

经典著作,值得一读,英文原版下载链接【免费】ModernRadarforAutomotiveApplications资源-CSDN文库。 2.1 基本雷达功能 雷达系统通过天线或天线阵列向空间辐射电磁能量。辐射的电磁能量“照亮”周围的目标。“被照亮”的目标拦截一些辐射能量&#xff0…

二十章总结

20.1线程介绍 世间有很多工作都是可以同时完成的。例如,人体可以同时进行呼吸、血液循环、思考问题等活动;用户既可以使用计算机听歌,也可以使用它打印文件。同样,计算机完全可以将多种活动同时进行,这种思想放在 Jav…

配置主机与外网时间服务器同步时间

目录 NTP服务简介 时间管理命令 第一步:更改当前主机所在地的时间 方法一:使用tzselect命令查询需要的时区 1、使用tzselect命令查询需要的时区 2、添加变量到 ~/.bash_profile 文件中,即追加类似的内容: 3、重新连接一个…

Flink(九)【时间语义与水位线】

前言 2023-12-02-20:05,终于写完啦,最近状态不错。刚写完又收到了她的消息哈哈哈哈,开心。 再去全力打拼一次,奋战一场,就算最后打了败仗也无所谓,至少你留下了足迹。 《解忧杂货店》 1、时间语义 …

团队git操作流程

项目的开发要求:(1)项目组厉员代码提交不少于20次 (2)项目组厉员每天提交不少于20次 (3)企业项目开发代码的每天的提交一般提交3-5次 (4)代码仓库的管理 git的基础操作流…

【CSP】202305-1_重复局面Python实现

文章目录 [toc]试题编号试题名称时间限制内存限制题目背景问题描述输入格式输出格式样例输入样例输出样例说明子任务提示Python实现 试题编号 202305-1 试题名称 重复局面 时间限制 1.0s 内存限制 512.0MB 题目背景 国际象棋在对局时,同一局面连续或间断出现3次或3…

会声会影2024软件还包含了视频教学以及模板素材

会声会影2024中文版是一款加拿大公司Corel发布的视频编软件。会声会影2024官方版支持视频合并、剪辑、屏幕录制、光盘制作、添加特效、字幕和配音等功能,用户可以快速上手。会声会影2024软件还包含了视频教学以及模板素材,让用户剪辑视频更加的轻松。 会…

【Linux 进度条小程序】缓冲区+回车换行

文章目录 回车与换行缓冲区举个栗子fflush函数倒计时小程序进度条小程序 回车与换行 回车和换行是不同的两个概念 回车:\r 使光标回到本行行首。 换行:\n使光标下移一格。 一般我们的键盘上的Enter键是回加换行键 在c语言中 \n 表示回车换行 效果和Ent…

iNet Network Scanner for Mac:简洁高效的WiFi网络扫描软件

随着无线网络的普及,WiFi网络已经成为我们日常生活中必不可少的一部分。无线网络的稳定性和速度对我们的工作和娱乐体验至关重要。因此,一款功能强大、简洁高效的WiFi网络扫描软件非常重要。今天,我们向大家推荐一款优秀的Mac平台WiFi网络扫描…

AI生成工具助力业界,黎万强投资。/微信支付和支付宝境外银行卡全面支持 | 魔法半周报

我有魔法✨为你劈开信息大海❗ 高效获取AIGC的热门事件🔥,更新AIGC的最新动态,生成相应的魔法简报,节省阅读时间👻 🔥资讯预览 AI应用一年半,IBM HR部省12000小时 华为沉默中,何时…

提高工厂能源效率的关键:工厂能耗监测平台

工业做为能源消耗的重要场所,所以节能减排对工业来讲是一个亟需解决的问题。除了对设备进行更新换代外,还需要能源管理消耗监测平台,帮助企业实现节能减排的目标。 工厂能源消费量非常庞大,能源比较难以监测与控制。传统能源的管…

《微信小程序开发从入门到实战》学习四十二

4.3 云开发文件存储 文件存储功能支持将任意数量和格式的文件(如图片和视频)保存在云端,支持 以文件夹的形式将文件归类。 在云开发控制台中,可以对云端保存的文件进行管理。 也可以通过文件存储API对文件进行上传、删除、移动…

每日股票价格 - 华为机试真题题解

每日股票价格 - 华为机试真题题解 题目描述 ​ 给定某只股票连续N天的价格列表stockPrices,其中stockPricesi表示股票某天的价格,请生成一个新列表,对应位置输出为:要想等到股票价格上涨,至少需要等待的天数,如果股票…

一个容器中填值,值太多不换行,而是调小字体大小和行高

<!-- clampLineHeight 重计算行高 --> <!-- clampTextSize 重计算字体大小 --> <!-- 这里的div高8mm, 宽6cm, 文本为text --> <div style"height:8mm;width:6cm;text-align:left"><span :style"{ fontSize: clampTextSize(text, 6cm…

Redis——某马点评day03——part2:秒杀业务异步优化

异步秒杀思路 原本的流程是如下所示&#xff0c;必须从开始到创建订单成功才会返回响应。就像饭店里面从下单到上菜都是一个人在服务&#xff0c;就导致服务员利用率很低&#xff0c;后一个顾客要等到前一个顾客上完菜才可以下单。 最简单的优化就是加员工&#xff0c;一次性…