说完Flow,再来看看它的两个子类,SharedFlow和StateFlow。
1. 冷流,热流
在说之前,要先看看这两种流有什么不同。冷流,指的是只有在消费者消费时才会生产数据。而热流,即便没有活跃的消费者,它们也可以存活,也就是说,数据在流外产生,然后传递给数据流,这样便不依赖收集者。
2. SharedFlow
相比于冷流Flow,SharedFlow是热流,它以广播的形式向流的所有收集者发射数据,所以,所有的收集者都可以接收到发射的数据。它之所以叫做热流,是因为它的实例独立于收集者的存在而存在,这一点区别于flow函数创建的Flow,它是冷流,并且为每个收集者单独启动。
SharedFlow永远不会完成,通过调用流的collect不会正常完成,通过launchIn函数调用也不会正常完成。SharedFlow的活跃收集者称为订阅者。
订阅者是可以被取消的。通常随着协程运行所在的scope的取消而取消。一个SharedFlow的订阅者总是可以取消的,所以每次发射数据前都会对其作出检查。流的多数终端操作符在SharedFlow上都不会完成,比如toList,但是流的裁剪操作符可以完成,比如take、takeWhile。
SharedFlow会保存指定数量的最新的数据,存储在replay cache里,每一个新的订阅者,都会先从获取replay cache中的数据,然后才是新发射的数据。replay cache的大小可在创建时通过参数replayCache指定。也可通过resetReplayCache重置replay cache。
1 | class EventBus { |
上面是通过MutableSharedFlow创建了一个流,也可以通过shareIn操作符,将一个冷流转化成为SharedFlow。在发射数据时,方法会挂起,直到所有的订阅者接收到了数据并返回。
和Channel类似,SharedFlow也提供了缓冲区的配置参数,
1 | public fun <T> MutableSharedFlow( |
replay表示存储的倒数最新事件的数量,buffer capacity则是缓冲区的容量大小,overflow为缓冲区数据满时,再发射数据时的行为策略,同样还是有三种:挂起等待、扔掉最新数据和扔掉最老的数据。
3. StateFlow
1 | public interface StateFlow<out T> : SharedFlow<T> { |
从接口定义可以看出,StateFlow是SharedFlow的子类,所以SharedFlow的特性它都有,区别在于,它只保存最新的数据,只有一个数据值,这个时候也可以称它为状态,所以的它的名字是StateFlow
1 | public fun <T> MutableStateFlow(value: T): MutableStateFlow<T> {} |
4. SharedFlow和StateFlow的不同
- 从创建方法可以看出,StateFlow有初始值,SharedFlow没有。这其实就是replay的大小不同,State固定为1,所以它需要有个初始值,而Shared不确定,所以不需要。
5. 应用
根据二者的特点,可以看出,SharedFlow适合应用于事件的场景,而StateFlow则是适合用于更新状态的场景。
6. 和LiveData对比
说完上面那些,感觉这些又和LiveData有些相似,其实它们之间还是有着一些不同。
LiveData是生命周期敏感的,因为它里面维护着Lifecycle,所以在进入到DESTROYED状态时,会取消当前的Observer,而Flow则是通过检查订阅者所在的协程是否还活跃来判断是否向其发射数据。
此外,LiveData是不防抖动的,也就是说,每次postValue都会通知给Observer,而StateFlow是防抖动的,因为它固定保留一个最新的状态值,在每次发射数据前,都会把要发射的数据和当前保存的值对比,如果相同则忽略这次发射,所以它是防抖动的。
最后说一句SharedFlow的shared,它的shared,共享,指的是它的数据对所有的收集者,也就是订阅者共享,同一个数据会广播给所有的订阅者,而冷流Flow,对于每一个收集者,都会执行生成数据的操作,所以它是独立的。