当前位置: 首页 > news >正文

Kotlin 流flow、ShareFlow、StateFlow、Channel的解释与使用

一、介绍

        随着Android接入kotlin开发,Android之前好多模式也渐渐被kotlin替代。开发模式也在做渐进的转型,从MVC到MVP在到MVVP以及现在的MVI等。

        流IO在java中和kotlin中使用率都是比较高的,场景很多。如Java的IO和NIO,再到我们现在使用的RxJava或者升级版的JxJava2。针对JxJava的流处理与转发机制。kotlin语言也自带了flow。

        早MVVM流行的时候,LiveData充当了数据的订阅与流转,但是我们知道,LiveData有一个问题,当Dialog或者当前设置发生旋转,会出现倒灌,这种行为是因为订阅生命发生变化。

针对这些问题,kotlin语言自带了flow流。

二、kotlin flow的介绍

        flow其实与RxJava比较类似,都是基于流在处理订阅的分发。这个flow也被最新的MVI模式所接受,替换了MVVM中的LiveData。

flow又区分冷流和热流。

冷流(Cold Flow)

  •  

    定义与工作原理:冷流是一种异步数据流,它按顺序发出值并正常或异常完成。冷流的特点是,只有当数据被消费者订阅(即调用collect方法后),生产者才开始执行发送数据流的代码。这意味着,如果没有消费者订阅,生产者不会发送任何数据。冷流通常是一对一的关系,即一个生产者对应一个消费者。

  •  

    创建方式:冷流可以通过多种方式创建,包括使用flow{}构建器、flowOfasFlow等方法。这些方法允许开发者根据需要创建冷流,以满足特定的数据生产需求。

  •  

    适用场景:冷流适用于那些不需要持续生产数据,而是在数据被消费时才进行生产的场景。例如,从数据库查询数据、计算结果等,这些操作只有在需要时才会执行。

热流(Hot Flow)

  •  

    定义与工作原理:热流与冷流的主要区别在于,无论是否有消费者订阅,生产者都会持续发送数据。热流支持多个消费者同时订阅,并且生产的数据可以被多个消费者共享。热流通过stateInshareIn操作符实现,可以将任何流转化为热流。

  •  

    适用场景:热流适用于需要持续提供数据给多个消费者的场景,如实时数据更新、传感器数据读取等。由于热流能够同时支持多个消费者,因此在需要共享数据给多个组件或界面时非常有用。

通过冷热流区分我们可以知道冷流和热流可以相互转换。冷流是一对一服务,热流是一对多服务。

这个也就导致,在后期的开发过程中,订阅和消费,流的互相转换。

1对多

1对1

 三、流的使用

        接下来主要介绍Flow、SateFlow、ShareFlow以及Channel的用法,冷流和热流互换。这些流基本都是用到了协程,所以不能直接使用。

3.1.Flow

flow:这个老六就是热流,只要你订阅就一直发,不停的发,只要emit中的都有记录,而且内部还维持了一个index,可以知道目前下发了多少次。热流不管是什么视乎订阅,都会有。

场景:热流是无线转发,一般使用在状态订阅转发,比如平台关闭了id,可以直接放进去,后面其他模块如果可以订阅,查找当前状态。包括配合webscoket可以做很多事情。

   var count=0val myflow= flow<String> {repeat(3,{count++emit("当前是=${count}")})}/*** flow是一直保持的,只要订阅一次,就会发送一次,而且上次的记录一直保持。collect需要通过协程来处理* */lifecycleScope.launch {myflow.flowOn(Dispatchers.Main).collect({textview.append("collect="+it+"\n")})myflow.collectIndexed { index, value ->textview.append("collectIndexed="+value+",${index}\n")}myflow.flatMapConcat { it->flow {emit("map=${it}")}}.collect({textview.append("${it}\n")})myflow.flatMapMerge {flow { emit("flatMapMerge=${it}")emit("MapMerge=最近")}}.collect({textview.append("${it}\n")})myflow.flatMapLatest {flow { emit("flatMapLatest=${it}")emit("flatMapLatest=最近")}}.collect({textview.append("${it}\n")})//热流转冷val reciver=myflow.produceIn(this).receiveCatching()textview.append("produceIn=${reciver.getOrNull()}\n")}

3.2 SateFlow

        状态流属于冷流,订阅会收到最近一次,如果订阅没有设置value,接受的是默认值,如果当前值没有变化,也不会发送,也就是当前值和上次会进行比较,如果一样不会继续订阅。是一对一,多次订阅,第一个collect完,后面将不会再收到订阅事件。

        val sateFlow=MutableStateFlow("")var num=0findViewById<View>(R.id.btn_click_state)?.setOnClickListener {lifecycleScope.launch {//默认连接的时候会收到最近一次的,如果最近都没有设置value或者emit,那么收到的是默认值sateFlow.value="ssssss"sateFlow.value="ssssss111111111111=${num++}"}}lifecycleScope.launch {sateFlow.collectIndexed { index, value ->textview.append("index=${index},value=${value}\n")}sateFlow.collect({textview.append("${it}\n")})sateFlow.emit("aaaa")}

3.3 ShareFlow

        shareflow和其他的flow不一样,在构造的时候有三个参数,第一个是replay重复多少次,和缓存次数,后面是缓存流类型,内部也是可以多次订阅,但是collectIndexed和collect类型只能出现一个。但是一个类型可以多次订阅

public fun <T> MutableSharedFlow(replay: Int = 0,extraBufferCapacity: Int = 0,onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
)

默认都为0,所以不会重复多次发送,这个就很好规避倒灌的问题。不会因为生命周期发生变化,内部出现多次订阅和消费的情况。

share流也是要在协程里的,emit协程体中,在emit之前不能进行订阅(collect),否则会出现阻塞,导致事件无法往下走,后面的emit无法发出,可以在多个协程体中进行订阅。

lifecycleScope.launch {//多次订阅也不会发送,只会优先发给第一个订阅的人shareFloow.collect {  value ->textview.append("1collect="+value+"\n")}shareFloow.collect {  value ->textview.append("2collect="+value+"\n")}shareFloow.collectIndexed { index, value ->textview.append("collectIndexed="+value+",${index}\n")}}findViewById<View>(R.id.btn_click_share)?.setOnClickListener {var count=0/*** flow是一直保持的,只要订阅一次,就会发送一次,而且上次的记录一直保持。collect需要通过协程来处理* */lifecycleScope.launch {shareFloow.emit("我在测试ShareFlow1")shareFloow.emit("我在测试ShareFlow2")shareFloow.collect {  value ->textview.append("in--1--collect="+value+"\n")}shareFloow.collect {  value ->textview.append("in--2--collect="+value+"\n")}}}

3.4Channel

        channel其实在很多地方都有,管道。Java中也有。这里也是可以通过管道channel来进行转发和订阅的。这个用法可以将管道转成flow,进行各种订阅

       //后订阅这,不再接受到之前的事件val channel= Channel<String>()var count=0findViewById<View>(R.id.btn_click_channel).setOnClickListener {lifecycleScope.launch{channel.send( "count=1")channel.send( "count=2")}}lifecycleScope.launch {//类似shareflow一直订阅,一直
//            channel.consumeEach {
//                textview.append("consumeEach=${it}\n")
//            }//只能订阅一次,且接受是第一次,后面不再接受
//            channel.consume {
//                textview.append("consume=${this.receive()}\n")
//            }//只消费一次,无法再继续接受,只接受第一次发送的事件
//            channel.consumeAsFlow().produceIn(this).consume{
//                textview.append("consumeAsFlow22=${receive()}\n")
//            }//会一直接受,和shareflow类似channel.consumeAsFlow().collect{textview.append("consumeAsFlow11=${it}\n")}}

他的订阅类型很多

1.consumeEach:一直订阅,只要发送就会接受

2.consume:单次消费,订阅后,只接受第一次,后面再发送也不会接受

3.channel.consumeAsFlow():转成热流

4.channel.consumeAsFlow().collect:热流的用法

四、总结

通过上面的分析,不管冷流还是热流以及管道,都有自己的特性。

冷热流以及管道可以互相转换

也可以转成LiveData

所以,大家在用的时候要注意,如果需要注意倒灌可以优先考虑ShareFlow,需要长期订阅用flow

注意:

但是sateFlow会出现倒灌情况,和LiveData一样,如何规避?其实可以用ShareFlow替代

相关文章:

Kotlin 流flow、ShareFlow、StateFlow、Channel的解释与使用

一、介绍 随着Android接入kotlin开发&#xff0c;Android之前好多模式也渐渐被kotlin替代。开发模式也在做渐进的转型&#xff0c;从MVC到MVP在到MVVP以及现在的MVI等。 流IO在java中和kotlin中使用率都是比较高的&#xff0c;场景很多。如Java的IO和NIO&#xff0c;再到我们现…...

【个人学习】JVM(7):方法区概述、方法区内部结构、垃圾回收等

方法区 栈、堆、方法区的交互关系 从线程共享与否的角度来看 ThreadLocal:如何保证多个线程在并发环境下的安全性?典型场景就是数据库连接管理,以及会话管理。 栈、堆、方法区的交互关系 下面涉及了对象的访问定位 Person 类的 .class 信息存放在方法区中person 变量存放…...

@Scheduled 定时任务自定义

简介 Scheduled 定时任务自定义可以通过SchedulingConfigurer实现。 SchedulingConfigurer 是 Spring Framework 中的一个接口&#xff0c;用于配置定时任务。当你需要对定时任务进行更高级别的定制时&#xff0c;这个接口就显得非常有用。 可以通过SchedulingConfigurer 接口…...

一种新颖的面试方式

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…...

【Linux】生产消费模型实践 --- 基于信号量的环形队列

你送出去的每颗糖都去了该去的地方&#xff0c; 其实地球是圆的&#xff0c; 你做的好事终会回到你身上。 --- 何炅 --- 基于信号量的环形队列 1 信号量2 框架构建3 代码实现4 测试运行 1 信号量 信号量本质是一个计数器&#xff0c;可以在初始化时对设置资源数量&#xf…...

Science Robotics 与蜜蜂群互动的蜂窝型机器人系统

蜜蜂&#xff0c;如黄蜂&#xff0c;蚂蚁和其他社会昆虫&#xff0c;建立大型自组织群体&#xff0c;通常被解释为自我调节的“超有机体”。这些超生物是生态系统的重要稳定剂&#xff0c;因此被认为是“关键物种”。例如&#xff0c;蜜蜂群落通过觅食授粉服务的生态效应对陆地…...

Vue 计算属性:优雅地处理数据逻辑

在 Vue.js 中&#xff0c;计算属性&#xff08;Computed Properties&#xff09;是一种非常实用的功能&#xff0c;它允许我们根据组件的响应式依赖进行缓存和派生状态。计算属性可以让我们以声明式的方式编写复杂的逻辑&#xff0c;而不必担心性能问题。 什么是计算属性&…...

C++中`union`

文章目录 C中的union什么是union&#xff1f;定义union示例一输出结果&#xff1a; 示例二修正后的代码解释输出结果结论 union的特性匿名union示例 union和struct的区别1. 内存布局2. 同时访问3. 用途 union和class的区别1. 数据成员2. 功能性3. 适用场景 在C编程中&#xff0…...

Linux——网络(1)

一、IPC&#xff08;进程间通信方式&#xff09; IPC&#xff1a;Inter Process Communication 共享内存&#xff08;最高效的进程间通信方式&#xff09; 虚拟地址 mmu(memory management unit ) 共享内存: 1.是一块&#xff0c;内核预留的空间 2.最高效的…...

【五】阿伟开始学Kafka

阿伟开始学Kafka 概述 人生若只如初见&#xff0c;阿伟心里回想起了第一次和Kafka见面的场景&#xff0c;记忆虽然已经有些模糊&#xff0c;但是感觉初次见面是美好的。积累了一些实战经验之后&#xff0c;阿伟感觉不能再是面对百度开发了&#xff0c;于是决心系统的学习一下Ka…...

Java—Arrays api

public static String toString(数组) //把数组拼接成一个字符串 public static int binarySearch(数组&#xff0c;查找的元素) //二分查找法查找元素 public static int[] copyOf(原数组,新数组长度) //拷贝数组 public st…...

Java - 基数排序算法介绍、应用场景和示例代码

概述 基数排序&#xff08;Radix Sort&#xff09;是一种非比较型整数排序算法&#xff0c;适用于整数或固定长度的字符串排序。它的基本思想是将待排序的元素分为多个关键字进行排序&#xff0c;通常从最低位&#xff08;最低有效位&#xff0c;Least Significant Digit, LSD…...

Django 后端架构开发:文件云存储,从本地存储到腾讯COS桶集成

⭐ Django 后端架构开发&#xff1a;文件云存储&#xff0c;从本地存储到腾讯COS桶集成 目录 ☁️ 文件云存储 - 项目使用云存储&#x1f4bb; 文件云存储 - 项目中使用本地存储&#x1f4dd; 文件云存储 - 概述和创建项目&#x1f310; 腾讯COS桶 - 概述&#x1f4da; 腾讯CO…...

【系统分析师】-综合知识-计算机网络与信息安全

1、要对消息明文进行加密传送&#xff0c;当前通常使用的加密算法是 报文认证算法&#xff1a;数字摘要 RSA 非对称加密&#xff0c;一般不用于明文 MD5 数字摘要 SHA-1 数字摘要&#xff0c;160位的消息摘要 HMAC 以一个密钥和一个消息为输入&#xff0c;生成一个消息摘要作…...

C++ | Leetcode C++题解之第363题矩形区域不超过K的最大数值和

题目&#xff1a; 题解&#xff1a; class Solution { public:int maxSumSubmatrix(vector<vector<int>> &matrix, int k) {int ans INT_MIN;int m matrix.size(), n matrix[0].size();for (int i 0; i < m; i) { // 枚举上边界vector<int> sum(…...

python动画:场景的线性变换展示

一&#xff0c;主函数 LinearTransformationScene 是 Manim 中用于展示线性变换的场景类。它通过在一幅背景和前景平面上展示向量和变换&#xff0c;帮助理解线性代数中的概念。 LinearTransformationScene(include_background_planeTrue, include_foreground_planeTrue, ba…...

HBase体系架构与环境搭建

这里写目录标题 一、常见的NoSQL数据库二、HBase的体系架构和表结构三、搭建HBasa环境1.本地模式2.伪分布模式全分布模式HA模式 一、常见的NoSQL数据库 NoSQL数据库的说明与定义 NoSQL是一种不同于关系数据库的数据库管理系统设计方式&#xff0c;是对非关系型数据库的统称。它…...

海思SD3403/SS928V100开发(16)Tsensor驱动开发

1. 前言 由于需要检测SD3403芯片内部实时温度,需要开发Tsensor传感器驱动和应用 查看手册发现SD3403内部有三个Tsensor传感器 可以参考之前我写的35系列平台Tsensor驱动开发记录 海思35系列平台Tsensor驱动开发(1)驱动编写_t sensor-CSDN博客 海思35系列平台Tsensor驱动…...

JVM类加载机制—JVM类加载过程

一、概述 代码编译后&#xff0c;就会生成JVM&#xff08;Java虚拟机&#xff09;能够识别的二进制字节流文件&#xff08;*.class&#xff09;。而JVM把Class文件中的类描述数据从文件加载到内存&#xff0c;并对数据进行校验、转换解析、初始化&#xff0c;使这些数据最终成…...

可变参数模板与包装器

抱歉&#xff1a;铁汁们&#xff0c;最近在做兼职&#xff0c;积累社会经验&#xff0c;多有拖欠&#xff0c;请多多包涵&#xff08;抱拳&#xff09; 引子&#xff1a;接上回我们讲了C11的几种新增&#xff0c;今天就来接着讲C11中比较有用的二个东西可变参数模板与包装器。…...

每日算法题 17---205.同构字符串

题目 205.同构字符串 要求 给定两个字符串 s 和 t &#xff0c;判断它们是否是同构的。如果 s 中的字符可以按某种映射关系替换得到 t &#xff0c;那么这两个字符串是同构的。每个出现的字符都应当映射到另一个字符&#xff0c;同时不改变字符的顺序。不同字符不能映射到同一…...

告别SIFT/ORB!用LoFTR+Transformer搞定低纹理场景的图片匹配(附Python实战代码)

低纹理场景图像匹配实战&#xff1a;LoFTR与Transformer的革新应用 在计算机视觉领域&#xff0c;图像特征匹配一直是三维重建、视觉定位等任务的基础环节。传统方法如SIFT、ORB依赖于特征检测器提取关键点&#xff0c;但在低纹理、重复图案或运动模糊场景中表现往往不尽如人意…...

7大应用场景:如何用计算机视觉技术彻底改变足球比赛分析?

7大应用场景&#xff1a;如何用计算机视觉技术彻底改变足球比赛分析&#xff1f; 【免费下载链接】sports computer vision and sports 项目地址: https://gitcode.com/gh_mirrors/sp/sports 在当今数字化体育时代&#xff0c;足球场精准定位技术正以前所未有的方式改变…...

OpCore-Simplify:零基础黑苹果配置终极指南,5分钟搞定复杂EFI

OpCore-Simplify&#xff1a;零基础黑苹果配置终极指南&#xff0c;5分钟搞定复杂EFI 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 还在为黑苹果配置…...

AI巨头集体“铸Token”:从ChatGPT到“数字员工工厂”,程序员的狂欢还是危机?

想象一下&#xff1a;你早上醒来&#xff0c;打开电脑&#xff0c;不是自己敲代码&#xff0c;而是对着一只“龙虾”说&#xff1a;“帮我把昨天的Bug修了&#xff0c;顺便给老板发份周报。” 这不是科幻——2026年3月&#xff0c;这事儿正在发生。 全球头部科技公司突然集体“…...

OpenClaw自动化测试框架:百川2-13B驱动的CI/CD辅助方案

OpenClaw自动化测试框架&#xff1a;百川2-13B驱动的CI/CD辅助方案 1. 为什么选择OpenClaw做测试自动化 去年我在重构一个中型前端项目时&#xff0c;遇到了测试覆盖率不足的老问题。手动补测试用例不仅耗时&#xff0c;还经常遗漏边界条件。当我尝试用传统测试生成工具时&am…...

ffmpegGUI:让FFmpeg视频处理变得简单的跨平台桌面工具

ffmpegGUI&#xff1a;让FFmpeg视频处理变得简单的跨平台桌面工具 【免费下载链接】ffmpegGUI ffmpeg GUI 项目地址: https://gitcode.com/gh_mirrors/ff/ffmpegGUI ffmpegGUI是一款基于FFmpeg的开源图形界面工具&#xff0c;它将命令行操作转化为直观的可视化交互&…...

ImageGlass架构深度解析:高性能Windows图像查看器的技术实现与优化策略

ImageGlass架构深度解析&#xff1a;高性能Windows图像查看器的技术实现与优化策略 【免费下载链接】ImageGlass &#x1f3de; A lightweight, versatile image viewer 项目地址: https://gitcode.com/gh_mirrors/im/ImageGlass ImageGlass作为一款轻量级、高性能的Win…...

Comsol光学仿真连续域束缚态BIC,te,tm模式耦合,透射光谱远场偏振矢量(导出数据计算)

Comsol光学仿真连续域束缚态BIC&#xff0c;te&#xff0c;tm模式耦合&#xff0c;透射光谱远场偏振矢量&#xff08;导出数据计算&#xff09;&#xff0c;所见即所得 【手指在键盘上停顿三秒】这周在实验室搞COMSOL光学仿真差点被边界条件逼疯&#xff0c;连续域束缚态(BIC)…...

WebSocket代理避坑指南:Nginx中proxy_set_header的3个关键配置项

WebSocket代理实战&#xff1a;Nginx中proxy_set_header的3个黄金法则 当在线聊天室的用户突然集体掉线&#xff0c;或是实时协作文档频繁失去同步时&#xff0c;问题往往藏在那些容易被忽视的HTTP头信息里。WebSocket作为现代实时应用的血管&#xff0c;其代理配置的精细程度直…...