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

Flow、SharedFlow、StateFlow 傻傻分不清楚

冷流与热流

Flow 与 SharedFlow、StateFlow 最大的区别在于 Flow 是冷流,而 SharedFlow、StateFlow 是热流。那冷流和热流又有什么区别?

冷流中的数据并不是一直存在内存中的,而且当收集的时候,才会产生,存储在内存中,等收集完后就会自动回收。

而热流中的数据是可以即使不收集的时候,也能产生数据,并把产生后就存储在内存中,等到收集完后,再把数据进行回收。

Flow

关于 Flow 的说明以及使用,可以参考「flow 操作符全解析」,这里就不过多进行说明了。

SharedFlow

在说明 SharedFlow 与 StateFlow 的区别前,我们可以先来了解 SharedFlow 是什么?

SharedFlow 就是观察者模式的一个具体实现,可以对观察者进行注册,当被观察者发生改变的时候,就会通知观察者,同时,SharedFlow 还可以存储之前的变化,即当 SharedFlow 变化后,才有观察者注册,这时观察者仍然能够收到之前的变化。

说了这么多,我们先来看看 SharedFlow 的简单使用吧,后续再详细说明。

首先,我们先创建 SharedFlow 对象:

private val sharedFlow = MutableSharedFlow<Int>()

然后进行数据提交更改:

            sharedFlow.emit(0)sharedFlow.emit(1)sharedFlow.emit(2)

然后进行收集:

            sharedFlow.collect { value ->println("value -> $value")}

我们来看下日志输出:

    

em??? 怎么啥都没有,这跟说好的不一样啊!

我们来看看 MutableSharedFlow 的构造参数:

public fun <T> MutableSharedFlow(replay: Int = 0,extraBufferCapacity: Int = 0,onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
): MutableSharedFlow<T> {
  • replay:指的是观察者注册后,能够收到多少个之前的通知,默认是为 0。
  • extraBufferCapacity:指的是当被观察者发送速度过快,或者观察者消化消息的速度过慢的时候,数据就会临时存储起来,而这里指的就是额外存储的个数,注意,是额外存储的个数,实际存储的个数是 replay + extraBufferCapacity
  • onBufferOverflow:由于 MutableSharedFlow 的存储空间是固定的,有可能会被超过限制,而 onBufferOverflow 则是标识当超过这个限制的时候,怎么进行处理,目前有三种选项:
    • BufferOverflow.SUSPEND:挂起,默认实现。
    • BufferOverflow.DROP_OLDEST:丢弃最老的值,保留最新的。
    • BufferOverflow.DROP_LATEST:丢弃最新的值,保留最老的。

通过上面的参数的讲解,我们就能够很清楚为什么上面的例子收不到消息了,所以,下面我们通过一个例子,简单测验这些值的功能。

class MainActivity : AppCompatActivity() {private val sharedFlow = MutableSharedFlow<Int>(1, 2, BufferOverflow.DROP_OLDEST)override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)GlobalScope.launch {sharedFlow.emit(0)sharedFlow.emit(1)sharedFlow.emit(2)sharedFlow.collect { value ->delay(1000)println("value -> $value")}}GlobalScope.launch {sharedFlow.emit(3)sharedFlow.emit(4)sharedFlow.emit(5)sharedFlow.emit(6)}}
}

日志输出为:

I/System.out: value -> 2
I/System.out: value -> 4
I/System.out: value -> 5
I/System.out: value -> 6

我们来逐步分析下日志:

  • 为什么有 2 ?

这是因为 replay 为 1,只会存储一位已发送的数据,所以,最开始发送的数据 0、1、2,只会保留最新的 2。

  • 为什么有 4、5、6 ?

这是因为 MutableSharedFlow 实际的缓存个数为 replay + extraBufferCapacity,也就是 1 + 2 = 3,所以有三个缓存位置,又由于 onBufferOverflow 为 BufferOverflow.DROP_OLDEST,所以,3、4、5、6 中只会保留最新的 4、5、6。

特别说明

有一点需要特别注意的,就是当 collect 运行结束后,即使使用 emit 发送数据,collect 里面的代码也不会执行。

另外,在测验中,我还发现另外一个坑点,就是把 collect 和 emit 放到同一个协程中运行,特别是 emit 在 collect 之后,会发现没有任何输出,就像这样:

        GlobalScope.launch {sharedFlow.collect { value ->delay(1000)println("value -> $value")}sharedFlow.emit(0)sharedFlow.emit(1)sharedFlow.emit(2)}

其实,这也很容易理解,因为 delay 的时候,该协程都阻塞了,emit 是不会执行到,而当 delay 之后,collect 都执行完成,这时再 emit,自然也不会再执行 collect 里面的代码。

StateFlow

StateFlow 其实就是一个特殊的 SharedFlow,就可以理解为是:

MutableSharedFlow(1,0, BufferOverflow.SUSPEND)

下面我们用个例子来看看是不是这个效果:


class MainActivity : AppCompatActivity() {private val stateFlow = MutableStateFlow(0)override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)GlobalScope.launch {stateFlow.emit(0)stateFlow.emit(1)stateFlow.emit(2)stateFlow.collect { value ->delay(1000)println("value -> $value")}}GlobalScope.launch {stateFlow.emit(3)stateFlow.emit(4)stateFlow.emit(5)stateFlow.emit(6)}}
}

日志输出:

I/System.out: value -> 2
I/System.out: value -> 6

大家可以根据我在上面的说明,看看能不能去理解为什么日志输出会是这样。

特别说明

  • StateFlow 和 SharedFlow 一样,collect 结束后,再 emit 也不会再次调起 collect 里面的代码,除非重新 collect。
  • StateFlow 除了可以使用 emit 提交更改,也可以使用这种方式进行更改:stateFlow.value = 1
http://www.lryc.cn/news/2419451.html

相关文章:

  • 【JavaScript】一文了解定时器的使用
  • Windows7系统explorer.exe文件问题
  • 约瑟夫环问题(队列,链表实现)- c++
  • 系统编程之文件IO(四)——初级IO(open、close、write、lseek)
  • JS中clientWidth offsetWidth innerWidth scrollWidth等区分
  • 经纬度有哪些格式
  • WAV文件格式详解
  • Ubuntu (安装问题,包括系统更新和软件安装)
  • 软件工程与计算II-12-详细设计
  • i386和X86各是什么意思 与arm的区别
  • 人脸对齐 matlab,常用几种人脸对齐算法ASM/AAM/CLM/SDM
  • 计算机网络知识之URL、IP、子网掩码、端口号
  • 磁力链接转换为种子文件 magnet to torrent
  • 深入浅出声学系统频率响应
  • Android开发者必须收藏的8个开源库,值得收藏!_android 开源鉴黄
  • 关于System.currentTimeMillis()的理解
  • python的np.meshgrid函数
  • 数字后端概念——shielding
  • 用hist()绘制直方图
  • [转]推荐一款新型 Java 网站内容管理系统,灵活、易用,运行稳定,轻松管理建设网站(附源码)
  • Linux tar命令详解,Linux备份解压文件_linux tar备份文件
  • 新手怎么炒外汇?
  • 【合唱】男女差八度的科学解释
  • handoop job工作运行的机制与原理详解
  • 20款最流行的免费定性数据分析工具
  • 主数据管理和实施
  • Linux 详解:最完整的入门指南_linux菜鸟入门指南
  • 【游戏】如何开发一款游戏:游戏开发流程及所需工具
  • 飞鸡:从小训练飞行的鸡能飞行吗?为什么野鸡能飞吗?是同一品种吗?今天自由思考
  • c++_ifstream,ofstream读写文件