LiveData去除粘性

open class NoStickLiveData<T : Any> : SafeLiveData<T> {
    private var mVersion:Int

    //反射拿到父类的field mObservers。
    private var mObservers:(java.lang.Iterable<java.util.Map.Entry<*, *>>)? = null

    private fun requireMObservers() : java.lang.Iterable<java.util.Map.Entry<*, *>> {
        val mOb = mObservers
        if (mOb == null) {
            var superClass: Class<*>? = javaClass.superclass
            while (superClass != null && superClass != Any::class.java) {
                if (superClass == LiveData::class.java) {
                    val field = superClass.getDeclaredField("mObservers")
                    field.isAccessible = true
                    val o = field.get(this)
                    mObservers = o as java.lang.Iterable<java.util.Map.Entry<*, *>>
                    break
                }
                superClass = superClass.superclass
            }
            return mObservers!!
        }
        return mOb
    }

    constructor() {
        mVersion = -1
    }

    constructor(data:T?) : super(data) {
        mVersion = 0
    }

    override fun setValue(value: T?) {
        mVersion++
        super.setValue(value)
    }

    override fun removeObserver(observer: Observer<in T>) {
        super.removeObserver(observer)
        removeObserverUnStick(observer)
    }

    /**
     * 追加不处理粘性的方式
     */
    fun observeUnStick(owner: LifecycleOwner, observer: Observer<in T>) {
        super.observe(owner, NoStickWrapObserver(this, observer = observer))
    }

    fun observeForeverUnStick(observer: Observer<in T>) {
        super.observeForever(NoStickWrapObserver(this, observer = observer))
    }

    fun removeObserverUnStick(observer: Observer<*>) {
        requireMObservers().let { iter->
            val foundList = ArrayList<Observer<in T>>()
            for (entry in iter) {
                val wrap = entry.key as? NoStickWrapObserver<*>
                if (wrap != null && wrap.observer == observer) {
                    wrap.asOrNull<Observer<in T>>()?.apply {
                        foundList.add(this)
                    }
                }
            }
            foundList.forEach {
                super.removeObserver(it)
            }
        }
    }

    private class NoStickWrapObserver<D:Any>(val self:NoStickLiveData<D>,
                                         val observer: Observer<in D>) : Observer<D> {
        private val version: Int = self.mVersion //标记进入的时候的版本

        override fun onChanged(value: D) {
            if (version < self.mVersion) {
                observer.onChanged(value)
            }
        }
    }
}

2024/05/21修改:微调代码,并追加混淆规则,否则编译的时候,基础库被混淆了,这里就无法反射到mObservers:

-keep class androidx.lifecycle.** { *;}

众所周知,LiveData是粘性的。即,当liveData赋值过(或者初始化默认有值),则当监听observe的瞬间,立刻回调给你的监听函数。

想要破除粘性,我翻阅了一些代码,写的五花八门。我这边也是将我个人的实现方案写在这里。
仔细阅读liveData源码,关键点是mVersion三个变化:

  • 空构造体赋值-1
  • 有参数构造体赋值0
  • 随后setValue每次++

而业务代码注册监听的函数observe(owner, observer) 或者observeForever(observer)
都是经过了包装,
LifecycleBoundObserver(owner, observer)
AlwaysActiveObserver(observer)

都放在了全局变量map,mObservers里面。key就是我们传入的变量observer。

直到removeObserver的时候,通过mObservers.remove(observer)来移除。

因此,类似的,我们只需要继承它,同时也借鉴:

  1. 也在setValue每次把自定义的版本号mVersion++以表征值的更新;
  2. 然后我们把用户代码的observe或者observeForever进行一次NoStickWrapObserver包装。只有当version有变大才通知即可;
  3. 移除的时候,就要考虑了。因为父类中mObservers存储的key,就是我们的NoStickWrapObserver,因此,我们需要将用户的observer,反射拿到父类对象map再找出我们的包装类,再去移除。

本代码的好处,
第一,反射只一次,因为mObservers在LiveData是final的全局变量,不会变化,性能损失可以忽略。
第二,与源代码LiveData的思想高度统一,通过wrap用户的observer存起来的思路。
第三,代码量极少;
第四,最重要的,你如果你想要原来的逻辑的LiveData就按照之前的写法;如果想注册一个后续监听的则调用observeUnStick即可,灵活且方便。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值