你应该知道的 Flow 的 shareIn 和 stateIn 操作符

本文介绍了Kotlin Flow的shareIn和stateIn操作符,用于将ColdFlow转换为HotFlow以提高性能。shareIn和stateIn的区别在于StateFlow能提供最后的状态,而SharedFlow不行。通过示例展示了如何配置这两个操作符以满足不同场景,如性能提升、事件缓存和数据缓存。同时,强调了避免在多次执行的代码中创建HotFlow以防止资源浪费。最后提到了使用这两个操作符时应注意的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

Flow 的 shareIn 和 stateIn 操作符可以转化一个 Cold Flow 到 Hot Flow:它可以把从上游 Cold Flow 中收到的数据广播给所有的订阅者(collectors/subscriber). 它通常用来提升性能, 甚至内部有缓存机制.

知识点普及:Cold Flow 一被订阅或者被观察的时候, 就会产生数据. 通常订阅者可以观察到所有的数据. 而 Hot Flow 是不管有没有订阅者订阅, 它都保持活跃, 并且可能发射数据.

在这个博客中, 你可以通过例子熟悉 shareIn 和 stateIn 操作符的用法. 你会学到如何配置它们去满足一些使用场景, 也会学到如何避免常见的陷阱.

底层数据生产者

继续之前文章的例子. 底层的 Flow 生产者是发射定位更新数据的. 它是一个 Cold Flow, 用 callbackFlow 实现. 每一个订阅者来订阅的时候, 否会触发 Flow 生产者的 block, 从而导致每次都会产生一个新的 callback 添加到 FusedLocationProviderClient 中

那让我们看看如何使用 shareIn 和 stateIn 操作符去优化上面的代码去满足不同的场景.

shareIn or stateIn?

先说明一个知识点. shareIn 和 stateIn 是不一样的. stareIn 操作符会返回一个 sharedFlow, 而 stateIn 会返回一个 StateFlow.

详细信息可以查看这里的文档: https://developer.android.com/kotlin/flow/stateflow-and-sharedflow

StateFlow 是一个特别的 SharedFlow. StateFlow 是 SharedFlow 派生类, StateFlow 的行为和 LiveData 的行为是类似的. 会发射最后一个状态给订阅者.

两者最大的区别是, StateFlow 允许你访问最后发射的状态. SharedFlow 是不可以的.

如果熟悉 LiveData 或者 RxJava 的 BehaviorSubhect, 你会瞬间明白 StateFlow 的行为.

提升性能

这些 Api 可以通过共享同一个 Flow 实例来提升性能. 当订阅者来订阅的, 不会多次创建 flow, 也不会和上述的情况一样每次都会让数据生产者每次执行内部的 block.

下面的例子中, LocationRepository 消费了 locationsSource 的 flow, 转化成了一个共享的 Flow 对象, 以便订阅者可以订阅同一个 Flow.

WhileSubscribed 策略是在没有订阅者的时候, 会取消上游的 Flow, 避免浪费资源. 但是有时候视图层可能发生一些系统行为导致的配置发生变化. 这里就会触发取消和重新订阅上游的 Flow. 所以官方十分推荐使用 WhileSubscribed(5000) 的策略. 表示 5 秒内如果都没有订阅者, 就取消, 这很好的避免了因为配置变化导致的资源浪费.

事件缓存

这个例子中. 我们的需求发生了变化. 有两点要求:

  1. 我们希望订阅者能一直收到位置的更新
  2. 新的订阅者能收到最后的 10 个位置信息数据.

width=“auto” height=“auto” src=“https://raw.githubusercontent.com/xiaojinzi123/images/master/20210604164953.png” />

我们可以使用 replay 参数, 设置 10 来缓存最后 10 个位置数据. 当订阅者来订阅了, 就会收到这十个值. 为了让底层的 Flow 生产者一直保持活跃. 我们可以使用 SharingStarted.Eagerly 策略. 即使没有任何的订阅者.

数据缓存

现在新的需求是, 我们只需要当订阅者订阅的时候, 能收到最后一个数据. 这时候我们可以使用 StateIn 操作符.

EmptyLocation 是传的一个默认值. 因为 StateFlow 需要一个默认值.

需要避免的问题

千万千万不要在一个方法中去使用 shareIn 或者 stateIn 去创建一个新的 Flow. 因为这会导致你创建无数个 Hot Flow, 在对应的 scope 取消的时候才能被销毁. 错误示范如下:

总结

shareIn 和 stateIn 操作符可以把 Cold Flow 转化为 Hot Flow, 从而提升性能. 但是使用上要特别注意, 不要在多次执行的方法或者代码块中使用 stateIn 和 shareIn 操作符去创建 Hot Flow. 这样会导致严重的资源浪费.

看都看完了, 关注一下我的公众号吧

### Flow 的概念及用法 Flow 是 Kotlin 协程库的一部分,提供了一种声明式的异步数据流处理机制。它能够高效地处理一系列的数据项,并支持背压(backpressure),这使得它可以很好地应对高频率产生的事件或者大量数据的传输场景[^1]。 #### 创建使用 Flow 创建一个简单的 Flow 可以通过 `flow` 构建器函数完成: ```kotlin val numbers = flow { for (i in 1..5) { emit(i) // 发射单个值给收集者 delay(100L) // 模拟耗时操作 } } ``` 要消费这个 Flow 中的数据,则可以调用其 `collect()` 方法: ```kotlin numbers.collect { value -> println(value) } // 输出:1, 2, 3, 4, 5 (每条消息之间有短暂延迟) ``` 为了优化性能并减少重复订阅的成本,还可以利用像 `stateIn`, `shareIn` 这样的运算符将冷流转换成热流[^2]。 ### Trigger 的概念及其在不同上下文下的含义 Trigger 在不同的编程框架技术栈中有多种解释。通常来说,触发器指的是当满足特定条件或发生某些预定义事件时执行的动作或逻辑单元。例如,在数据库管理系统中,Triggers 被用来响应表上的插入、更新或删除操作;而在前端 Web 开发里,它们可能关联着用户的交互行为如点击按钮等。 对于 Salesforce 平台而言,Before-save Triggers 特指一种特殊的流程构建组件,允许开发者编写自定义业务规则来修改记录属性或阻止保存动作的发生,从而确保数据的一致性完整性。 ### 结合实例说明两者关系 在一个典型的移动应用程序架构设计案例中,假设有一个聊天功能模块需要实时同步最新的对话列表至客户端设备上显示出来。此时就可以采用如下方案: - 使用 **Flow** 来监听服务器端推送过来的新消息通知; - 当接收到新消息后作为 **trigger** 去驱动 UI 层重新加载展示内容。 这种模式不仅简化了代码结构而且提高了系统的灵活性与扩展能力。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值