在Kotlin的协程库kotlinx.coroutines
中,StateFlow
和SharedFlow
是两种用于处理事件流的API,它们有相似之处,但在设计上的初衷和内在机制上有明显区别。
这次我们就对StateFlow
和SharedFlow
进行深入对比:
StateFlow
和 SharedFlow
概述
StateFlow:
一种用于持有单一最新状态值并发射给多个观察者的热流。适合用于状态管理场景,例如表示UI状态。
和livedata比较像,有新数据可以通知collect的一方
同时又具有flow的所有特点,比如可以挂起,切换线程
SharedFlow:
一种通用热流,可以发射事件流而不是仅限于持有最新状态。适合处理事件总线、观察者模式等场景。
也就是一对多的关系,可以有多个collector
同时又具有flow的所有特点,比如可以挂起,切换线程
和上面的StateFlow不同的是,这个不能主动通知collect方,需要不断emit元素,也就是利用了flow的功能
设计初衷不同
StateFlow
的设计是为了取代ConflatedBroadcastChannel
,用于表示状态,并且总是持有最新的状态值。SharedFlow
的设计是为了提供一个通用的、可共享的事件流机制,支持事件的重播、缓存等。
状态持有和重播不同
StateFlow:
总是持有最新的状态值。
新的观察者会立即收到当前持有的状态值。
流中的每个新值都会覆盖之前的值,即只有最新的状态值会被保留。
SharedFlow:
不会持有单一最新状态值(除非配置了重播缓存)。
可以配置重播机制(
replay
参数)以指定新的观察者接收之前多少个已发射的值。可以配置不同的缓冲策略,如
BufferOverflow
来定制事件丢弃策略。
类型层次结构
StateFlow
继承自SharedFlow
,所以它是SharedFlow
的一种特化实现。
public interface StateFlow<out T> : SharedFlow<T> { /** * The current value of this state flow. */ public val value: T }
应用场景
StateFlow:适用于状态管理场景,例如在ViewModel中表示UI状态。因为它始终持有最新的状态,能确保观察者总能获得最新的状态。
SharedFlow:更加灵活和通用,适用于事件处理、事件总线、消息队列等场景。尤其适合需要重播特定数量的历史事件或者处理事件丢弃政策的场景。
使用对比
StateFlow 使用示例
val _stateFlow = MutableStateFlow<Int>(0) // Initial state val stateFlow: StateFlow<Int> = _stateFlow // Collect values stateFlow.collect { value -> println("StateFlow value: $value") } // Emit new state _stateFlow.value = 1
SharedFlow 使用示例
val _sharedFlow = MutableSharedFlow<Int>(replay = 2) // Buffer size of 2 val sharedFlow: SharedFlow<Int> = _sharedFlow // Collect values sharedFlow.collect { value -> println("SharedFlow value: $value") } // Emit new values _sharedFlow.emit(1) _sharedFlow.emit(2) _sharedFlow.emit(3)
重要的API
StateFlow
value
:获取或设置当前的状态值。collect
:收集状态值的变化。
SharedFlow
emit
:发射一个新事件。collect
:收集事件。replayCache
:获取重播缓存。
此外,两者还有collectLatest
接口,下次我们再来详细对比看看
选择指南
选择
StateFlow
:如果你的应用场景需要在多个观察者之间共享最新的状态,并且没有兴趣保留状态的历史记录,那么StateFlow
是你的最佳选择。选择
SharedFlow
:如果你需要一个更通用的事件流机制,并且可能需要缓存和重播事件,SharedFlow
提供了更强的灵活性和定制性。