1.4.0协程之StateFlow和SharedFlow介绍

今天,我们很高兴地发布Kotlin Coroutines库的1.4.0版。该版本重点关注已稳定的StateFlowSharedFlow API。当Kotlin Coroutines异步执行的上下文中需要状态管理,StateFlow和SharedFlow便是被设计用于这种场景。

img

Kotlin中的Flow API旨在异步处理按顺序执行的数据流。Flow本质上是一个Sequence。我们可以像对Kotlin中Sequence一样来操作Flow:变换,过滤,映射等。Kotlin SequencesFlow的主要区别在于Flow可以挂起。

Flow中,你可以在任何地方挂起:例如builder函数中,或Flow API提供的运算符中。 Flow的挂起行为就像受背压控制一样,但是不需要你做任何事——编译器将完成所有工作。

Flow就像使用Kotlin Sequences一样简单。但提供了所有响应式编程的优点,而无需管理背压。

Flow是一套方便的API,但它不提供部分场景所必需的状态管理。例如,一个流程可能具有多个中间状态和一个终止状态。下载文件就是这类流程的一个示例:下载持续的时间中,中间状态可能会从“开始”过渡到“下载中”标记,然后终止状态是“成功”或“失败” 。在这种情况下,无论下载是否成功,我们只对结果感兴趣。

使用Flow API实施上述方案时,我们希望状态的变动能通知到会有所动作的观察者。借鉴历史,我们建议使用ConflatedBroadcastChannel。但是,ConflatedBroadcastChannel对于手头的任务来说有点太复杂了。另外,使用通道进行状态管理时会出现一些逻辑上的不一致。例如,可以关闭或取消通道。但由于无法取消状态,因此在状态管理中无法正常使用!

我们已决定弃用ConflatedBroadcastChannel,取而代之引入一对新的API——StateFlowSharedFlow

StateFlow

StateFlow有两种类型: StateFlowMutableStateFlow:

状态由其值表示。任何对值的更新都会反馈新值到所有流的接收器中。

让我们看一下如何使用新的API来实现我们前面描述的文件下载示例。

本示例向客户端暴露了* state的不可变版本,并在内部管理可变状态(state*)。在下载函数中,我们先初始化了内部状态值:** state.value = DownloadStatus.INITIALIZED*。然后通过进度指示数字来更新内部状态。最后我们使用终止值(指代下载状态)更新 state *。

如你所见,没有channel API。我们没有发布额外的协程,也不需要学习新的概念。只是依赖变量实现的简单命令式代码,并向客户端暴露了Flow类型的* state*。

SharedFlow

如果只是需要管理一系列状态更新(即事件流),而非管理状态,该怎么办?对于这个用例,我们有一套名为SharedFlow的新API。如果你对发出的一连串值感兴趣,则这API十分方便。例如,根据数据流计算滑动平均值。

共享流只是一个流,其中包含可用作原子快照的replay cache。每个新的订阅者会先从replay cache中获取值,然后才收到新发出的值。

除了SharedFlow,我们也提供了MutableSharedFlow

MutableSharedFlow可用于从挂起或非挂起的上下文中发射值。顾名思义,可以重置MutableSharedFlow的replay cache。而且还将订阅者的数量作为Flow暴露出来。

实现自己的MutableSharedFlow可能很麻烦。因此,我们提供了一些使用SharedFlow的便捷方法。

要使用上面的函数初始化MutableSharedFlow实例,我们可以指定重播给新订阅者的值的数量,缓冲区容量以及缓冲区已满时该怎么办。例如,如果缓冲区已满,我们可以选择挂起流。

如果你已经有一个Flow实例,并且希望使其能被共享,则可以使用新的运算符Flow.shareIn

总结

新的StateFlow和SharedFlow API提供了在Kotlin程序中更优雅使用协程管理状态的方案。和使用broadcast channel从流上下文中发布状态变更相比,它们更加简单和直观。

StateFlow和SharedFlow目前还处于实验阶段。请尝试、测试、破坏,然后将你的反馈分享给我们!让新的API稳定是我们的首要任务之一。

更多相关的详细信息,及Kotlin Coroutines的新功能,请观看Kotlin 1.4在线活动中Vsevolod Tolstopyatov的演讲。

此条目发表在官方分类目录。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用*标注