前言
LiveData是Google提供的一个数据封装类,值改变的时候会自动通知观察者。
LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
为了解决的问题
在MVVM模式中,LiveData+ViewModel是使用非常频繁的组合,有时候我们需要在LiveData值改变的时候通知界面做一些事情,比如页面跳转,弹窗,Toast之类,但是LiveData+Observer的特性是值每次绑定的时候就会触发一次,如果没处理好,就会有莫名其妙的Toast或者页面跳转出问题。
我们可以通过消费掉LiveData值之后置空LiveData,但这完全不优雅,不利于v和vm的分离,界面上不应该操作LiveData的值。
Google建议我们封装一个一次性的LiveData数据。
本文提供一个思路:
对MutableLiveData值进行封装,进一步创建一个MutableLiveData子类OneOffLiveData的方式解决这个问题。
首先,需要只能消耗一次的值
如下,一个封装类OneTimeEvent,通过标志位来判断是否调用过
/**
* 一次性的事件
*/
class OneTimeEvent<T>(private val event: T) {
private var flag = true
/**
* [func]只会生效一次,
* [call]和[get]只会成功调用一次
*/
fun call(func: (T) -> Unit) {
if (flag) {
flag = false
func(event)
}
}
/**
* 只会得到一次值,
* [call]和[get]只会成功调用一次
*/
fun get(): T? = if (flag) {
flag = false
event
} else {
null
}
}
两个扩展函数,方便使用该扩展类
/**
* 返回一个一次性事件的封装对象
*/
fun <T> T.oneOff() = OneTimeEvent(this)
/**
* 发射一次一次性事件
*/
fun <T> MutableLiveData<OneTimeEvent<T>>.postOneOff(someOneOff: T) {
this.postValue(OneTimeEvent(someOneOff))
}
使用
object TipDialog {
val tipDialogLiveData = MutableLiveData<OneTimeEvent<MessageType>>()
}
观察:
TipDialog.tipDialogLiveData.observe(this, Observer { oneTime ->
oneTime?.call { messageType ->
....
}
}
进一步,把一次性事件封装到LiveData子类
class OneOffLiveData<T> : MutableLiveData<OneTimeEvent<T>>() {
/**
* 替代掉LiveData的observe方法
*/
fun observeOneOff(owner: LifecycleOwner, func: (T?) -> Unit) {
observe(owner, Observer {
it?.call(func)
})
}
}
使用和原本常用的MutableLiveData基本一致
object TipDialog {
val tipDialogLiveData = OneOffLiveData<Message>()
}
观察:
TipDialog.tipDialogLiveData.observeOneOff(this) { message ->
...
}
网友评论