专栏名称: 郭霖
Android技术分享平台,每天都有优质技术文章推送。你还可以向公众号投稿,将自己总结的技术心得分享给大家。
目录
相关文章推荐
郭霖  ·  StateFlow 和 ... ·  1 周前  
鸿洋  ·  一个大型 Android 项目的模块划分哲学 ·  3 天前  
stormzhang  ·  年底扣税变多了 ·  3 天前  
鸿洋  ·  理解Android ... ·  5 天前  
51好读  ›  专栏  ›  郭霖

StateFlow 和 SharedFlow 之间的区别

郭霖  · 公众号  · android  · 2024-11-11 08:00

正文



/   今日科技快讯   /


近日,特斯拉 CEO 埃隆・马斯克周四在 X 平台上透露,特斯拉正在改进 Optimus 机器人的设计,以解决生产过程中的关键瓶颈问题。


特斯拉的 Optimus 机器人可能是该公司未来最令人兴奋的产品之一。马斯克此前曾表示,他相信这款机器人将是有史以来最受欢迎的产品,因为其具备强大的功能。

/   作者简介   /


大家周一好,新的一周继续努力!


本篇文章转自小墙程序员的博客,文章主要分享了 Compose 中 StateFlow 和 SharedFlow 之间的区别,相信会对大家有所帮助!


原文地址:

https://juejin.cn/post/7397019920284074022


/   前言   /


在之前深入理解 Jetpack——LiveData 这篇文章中,我们提到过使用 LiveData 的数据丢失和数据重放的问题。因此在 Android 中,目前是更推荐使用 SharedFlow、StateFlow 来替代 LiveData。这篇文章就介绍一下,SharedFlow和 StateFlow 之间的区别。


/   Flow 与 SharedFlow 和 StateFlow 的区别   /


在开始介绍 SharedFlow和 StateFlow 之间的区别之前,我们先来看看为什么不直接使用 Flow,而是创建新的 SharedFlow和 StateFlow 呢?


这是因为普通的 Flow 数据不是共享的,每次调用 collect 都会触发新的数据流。代码如下所示:


suspend fun testCollect() {
    // 打印 0 1 2
    getFlow().collect {
        println("first collect $it")
    }
    // 打印 0 1 2
    getFlow().collect {
        println("second collect $it")
    }
}

private suspend fun getFlow() = flow {
    emit(0)
    emit(1)
    emit(2)
}

同时,由于 Flow 是冷流,因此它需要消费端主动调用 collect 才能触发数据的流动, 而一旦消费端停止 collect 或者生产端结束,Flow 会自动关闭。除此之外, Flow 也没有数据缓存的机制,无法主动获取当前发送的数据。


与 Flow 不同的是,SharedFlow 和 StateFlow 是热流,不依赖 collect 来触发数据的流动。同时 SharedFlow 和 StateFlow 都支持数据共享的,内部也有缓存,可以获取发送的数据。如下图所示:



/   StateFlow   /


StateFlow 中文翻译是状态流,主要用于共享一个状态的数据流时。在功能上,StateFlow 可以说就是一个 LiveData。


StateFlow 和 LiveData 一样数据会重放数据,代码示例如下。当 stateFlow 先发送数据 1,增加一个新的监听时,数据 1 会重新发送给这个新的监听者。需要注意的是,相同的数据是不会重放的,因为 StateFlow 内部会对数据进行判重的处理。


// 创建 StateFlow 必须需要一个默认值
val stateFlow = MutableStateFlow(0)

suspend fun testStateFlow() {
    collectStateFlow()
    delay(100)
    stateFlow.emit(1)
    // 第二次 collect 也会获取到之前发送过的 1
    collectStateFlow()
}

private fun collectStateFlow() {
    CoroutineScope(Dispatchers.IO).launch {
        stateFlow.collect {
            println("collect $it")
        }
    }
}

StateFlow 和 LiveData 一样数据会丢失数据。当 StateFlow 连续 emit 时,我们只会获取最新的数据 3,StateFlow 会抛弃旧的数据。


suspend fun testStateFlow() {
    CoroutineScope(Dispatchers.IO).launch {
        stateFlow.collect {
            delay(200) // 模拟消费数据时的耗时
            println("collect $it")
        }
    }
    stateFlow.emit(1)
    stateFlow.emit(2)
    stateFlow.emit(3)
}

/   SharedFlow   /


不同于 StateFlow 和 LiveData,默认配置下 SharedFlow 既不会重放数据,也不会丢失数据。如果你想要避免 LiveData 的重放数据和丢失数据的问题,可以使用默认配置下的 SharedFlow。


val sharedFlow = MutableSharedFlow(
    replay = 0, // 重放数据个数
    onBufferOverflow = BufferOverflow.SUSPEND  // 缓存溢出策略
)


SharedFlow 的构造方法如上所示。它有两个参数非常重要,分别是 replay,代表重放数据个数,默认情况下为 0;另一个是 onBufferOverflow,代表缓存溢出策略,默认情况下为 BufferOverflow.SUSPEND。BufferOverflow 有三种,分别是:


  • BufferOverflow.SUSPEND:缓存溢出时挂起 emit 方法

  • BufferOverflow.DROP_LATEST:缓存溢出时丢失最新的数据

  • BufferOverflow.DROP_OLDEST:缓存溢出时丢失最旧的数据


SharedFlow 可以根据业务的需要对其行为进行设置。如果说你想要 SharedFlow 的行为就与 StateFlow 一样,就可以使用如下的配置,不过这种情况是直接建议使用 StateFlow。从这里可以看出,StateFlow 实际上只是 SharedFlow 的一个特例, SharedFlow 的功能更加的全面。


val shared = MutableSharedFlow(
    replay = 1,
    onBufferOverflow = BufferOverflow.DROP_OLDEST
)
shared.tryEmit(initialValue) // 设置初始值
val state = shared.distinctUntilChanged() // 过滤掉相同的数据

推荐阅读:

我的新书,《第一行代码 第3版》已出版!

原创:写给初学者的Jetpack Compose教程,edge-to-edge全面屏体验

Android vold(卷管理)传记


欢迎关注我的公众号

学习技术或投稿



长按上图,识别图中二维码即可关注