Android开发经验谈Android技术知识Android开发

LiveData的一次性事件封装

2020-04-11  本文已影响0人  Coair_Scarlet

前言

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 ->
    ...
}
上一篇 下一篇

猜你喜欢

热点阅读