LiveData的一次性事件封装

作者: Coair_Scarlet | 来源:发表于2020-04-11 22:56 被阅读0次

    前言

    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 ->
        ...
    }
    

    相关文章

      网友评论

        本文标题:LiveData的一次性事件封装

        本文链接:https://www.haomeiwen.com/subject/bblpmhtx.html