Flow是Google官方提供的一个类似于RxJava的响应式编程模型。它是基于Kotlin协程的。 它相对于Rxjava具有以下特点:
- 具有更友好的API,学习成本较低。
- 结合协程的作用域,当协程被取消时,Flow也会被取消,避免内存泄漏。
LiveData的不足
LiveData只能在主线程更新数据,虽然提供了postValue用于后台线程,但其实postValue也是需要切换到到主线程的,这意味着当我们想要更新LiveData对象时,我们会经常更改线程,如果在修改LiveData后又要切换回到工作线程那就更麻烦了,同时postValue可能会有数据丢失的问题。
postValue只是把传进来的数据先存到一个变量中,然后往主线程抛一个Runnable,在这个Runnable里面再调用setValue来把存起来的值设置上去,并回调观察者们。而如果在这个Runnable执行前多次 postValue,其实只是改变这个变量的值,并不会再次抛另一个Runnable,这就会出现值覆盖的问题,从而造成数据丢失。
冷流和热流
冷流:只有订阅者订阅时,才开始执行发射数据流的代码。并且冷流和订阅者只能是一对一的关系,当有多个不同的订阅者时,消息是重新完整发送的。 热流:无论有没有订阅者订阅,事件始终都会发生。当热流有多个订阅者时,热流与订阅者们的关系是一对多的关系,可以与多个订阅者共享信息。
首先,贴上引用
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0'
implementation "androidx.activity:activity-ktx:1.3.1"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0-beta01"
SharedFlow的使用
在ViewModel中发送数据
class MainViewModel : ViewModel() {
val sharedFlow = MutableSharedFlow<String>()
init {
viewModelScope.launch {
sharedFlow.emit("Hello")
sharedFlow.emit("Uncle Xing")
}
}
}
在Activity中接收数据
val mainViewModel: MainViewModel by viewModels()
lifecycleScope.launch {
mainViewModel.sharedFlow.collect {
Log.i(tag, "value:$it")
}
}
将冷流转化为SharedFlow
val coldFlow = flow {
for (i in 1..3) {
delay(1000)
emit(i)
}
}.shareIn(viewModelScope, WhileSubscribed(1000), 1)
shareIn有三个参数:
- scope:共享开始时所在的协程作用域范围。
- started:控制共享的开始和结束的策略,此参数有三个值,Lazily:当首个订阅者出现时开始,在scope指定的作用域被结束时终止;Eagerly:立即开始,在scope指定的作用域被结束时终止;WhileSubscribed:在没有收集器的情况下取消上游数据流。
- replay:状态流的重播个数。
Whilesubscribed
WhileSubscribed策略会在没有收集器的情况下取消上游数据流,他支持两个参数:
public fun WhileSubscribed(
stopTimeoutMillis: Long = 0,
replayExpirationMillis: Long = Long.MAX_VALUE
): SharingStarted =
StartedWhileSubscribed(stopTimeoutMillis, replayExpirationMillis)
}
- stopTimeoutMillis:指最后一个订阅者结束订阅与停止上游流的时间差,单位是毫秒,默认值是0,即立刻停止。有时可能并不想因为视图有几秒钟不再监听就结束上游流,比如当用户旋转设备时,原来的视图会先被销毁,然后数秒钟内重建。
- replayExpirationMillis:表示数据重播的过时时间,如果用户离开应用太久,此时您不想让用户看到陈旧的数据,你可以用到这个参数。
StateFlow使用
StateFlow继承于SharedFlow,是SharedFlow的一个特殊变种,StateFlow与LiveData比较相近,所以可以替换LiveData。
class MainViewModel : ViewModel() {
var count = 1
val valueFlow = MutableStateFlow(count)
fun changeValue() {
count++
valueFlow.value = count
}
}
在ViewModel上游不断发送值,View层通过collect函数去获取到上游发送的数据。StateFlow只有在值改变时才会返回,如果发生更新但值没有变化时,StateFlow不会回调collect函数,这也是跟SharedFlow的主要区别,SharedFlow支持发出和收集重复值。
val mainViewModel: MainViewModel by viewModels()
lifecycleScope.launchWhenCreated {
repeatOnLifecycle(Lifecycle.State.STARTED) {
mainViewModel.valueFlow.collect {
Log.i(tag, "value:$it")
}
}
}
观察StateFlow需在协程中,因此我们需要协程构建器:
- lifecycleScope.launch : 立即启动协程,并且在本 Activity或Fragment 销毁时结束协程。
- LaunchWhenStarted和LaunchWhenResumed:在lifecycleOwner进入X状态之前一直等待,又在离开X状态时挂起协程。
官方推荐用repeatOnLifecycle来构建协程,当视图处于 STARTED 状态时会开始收集流,并且在 RESUMED 状态时保持收集,最终在视图进入 STOPPED 状态时结束收集过程。
|