美文网首页
Android不使用反射,完成LiveDataBus

Android不使用反射,完成LiveDataBus

作者: liyihuanx | 来源:发表于2021-10-21 21:26 被阅读0次

    LiveDataBus大家都很熟悉了,网上也有很多通过反射实现的LiveDataBus。但是通过反射实现的代码比较混乱,也比较难以理解。这里给出一版通过代码实现的。更加的简洁优雅~

    首先来看一下LiveData原理

    一般我们都是这样使用的,创建一个LiveData去发送数据,在你想观察的地方去注册。这样只要数据发射,你就能拿到你想要的数据了。


    image.png

    下面就是你再使用红框语句时的调用流程


    image.png

    所以首先进入 observe 方法看一看

    image.png

    这样我们创建的LifecycleBoundObserver(observe方法中的new Observer
    就和宿主(observe方法中传入的this) 建立了联系。

    所以宿主每次生命周期的变化都会调用到
    LifecycleBoundObserver的onStateChanged
    而从代码中也可以看到,在宿主生命周期是DESTROYED时,会主动移除掉当前mObserver,完成自动反注册,这里注意要把mObservers 和 mObserver分清楚

    image.png

    这里有几点需要注意一下
    1.LiveData中的mObservers是一个Map,还有一个mVersion字段默认等于 -1


    image.png

    2.LifecycleBoundObserver 继承 ObserverWrapper
    里面有mObserver,其实就是保存自己
    还有一个mLastVersion字段,默认等于 -1


    image.png

    接下来继续进入activeStateChanged方法,其他方法不多解释。
    这里直接进入dispatchingValue
    可以看到dispatchingValue不管走哪边都会进入considerNotify


    image.png image.png

    接下来看considerNotify


    image.png

    看到这里我相信你已经知道,我们为啥能再onChanged拿到数据了

        viewModel.liveDataObject.observe(this, new Observer<Bean>() {
            @Override
            public void onChanged(Bean data) {
                  接收数据
            }
        });
    

    接下来看一下,postValue和setValue

    可以看到setValue是有注解MainThread的,表示只能在主线程中使用
    而postValue没有,把某事件抛到主线程去了


    image.png

    再来来看一下,postValue在切换到主线程中都干了些啥,我们发现他的Runnable中的方法,最终还是执行了setValue。


    image.png

    所以这样看
    postValue只不过是可以在子线程执行,但是消息发送最终还是要到主线程,且执行setValue
    而setValue就只能在主线程执行了

    在执行了setValue或者postValue后,mVersion+1,接着直接进入到considerNotify


    image.png

    黏性事件怎么来的?

    为了造成黏性事件,我再注册观察者之前就将数据发送出去,然后通过按钮点击再去注册一个观察者,我们能发现,即使是之前发送的数据,仍然能够接受得到,这就是黏性事件。


    image.png

    造成的原因就是mLastVersion 和 mVersion

    image.png

    实现自己的LiveDataBus

    LiveData基本的都了解过了,接下来自己实现一个,既可以接受黏性事件,又可以接受普通事件。

    怎么控制黏性事件

    其实原本的代码就是可以发送事件的,只不过不能自由的控制黏性事件,
    **如果我们能用一个变量去标志就好了,比如这样标志一个receiveSticky变量**
    为true就是接受黏性事件,那么调用方法发送数据
    为false的话就会,跳过此方法

    
    if (observer.mLastVersion >= mVersion) { 
         return;
    }
    observer.mLastVersion = mVersion;
    if(receiveSticky){
         observer.mObserver.onChanged((T) mData);
    } else {
         // 处理普通事件
    }
    
    

    在假设我们能直接在源码添加这个字段的话,那这个receiveSticky从哪里来呢?
    1.发送者的角度:从 postValue 和 setValue 入手
    比如改写成 postValue(data,receiveSticky)
    这样有个弊端,这样只能统一发送黏性或者非黏性,这样如果多个宿主监听同一个消息,而有些需要黏性,有些不需要,这样就很难控制

    2.从接收者的角度:从observer入手
    我们知道我们传入的observer,在包装成LifecycleBoundObserver后,才有mLastVersion。那我们可以参考一下这种思路

    比如:LifecycleBoundObserver包装一下,有了mLastVersion
    那么:我们将传入的Observer也包装一层,在创建的时候传入receiveSticky就好了
    就像这样:(当然这不是完整版,这只是记录一下思路)

    image.png

    怎么保证接收的是同一个事件

            liveData.postValue
            viewModel.liveData.observer(this , Observer {
    
            })
    

    一般我们都是这样发送接收的,这个LiveData都是同一个才能接收同一份数据。
    所以我们也必须在LiveDataBus保证是同一个LiveData才行。

    还是同样的思路,要区分LiveData,就给LiveData加名字就行了呗
    那我就再给LiveData包装一层,让调用者传入名字去生成
    生成完了就保存下来,以后就用名字去找到对应的LiveData
    就好比:

    image.png

    那么他的用法就是这样的:接收消息的有点过于复杂了。


    image.png

    既然observer是LiveData里面的方法,
    而每次发送消息时间都是StickyObserver(sticky, Observer())
    这样我们就可以在我们的包装类中去复写一下observer,比如:

    image.png

    这样发送接收数据就会变成,比之前稍微好一些


    image.png

    如何解决普通事件的接收

    在上面我们其实没对普通事件做处理
    我们通过sticky能判断接不接受黏性事件
    但是我们不知道在我们注册之前,有没有消息事件发送

    override fun onChanged(t: T) {
        if (sticky) {
           observer.onChanged(t)
        } else {
            // 普通事件
        }
    }
    

    回想一下,黏性事件是怎么产生的?
    简单的认为,observer.mLastVersion(Observer的) < mVersion(LiveData的) 就会产生黏性事件
    所以我们也可以模仿一下,弄两个变量去判断


    image.png

    在我们的LiveDate中


    image.png

    在我们的observe中会被改写成这样


    image.png

    所以显然不能完全完全按照源码照抄
    那黏性事件之所以会被发送出去,
    就是在StickyObserver初始化时mLastVersionmLiveDataVersion没对齐,
    导致if (mLastVersion >= stickyLiveData.mLiveDataVersion) {} 没进入
    所以进入if条件就有黏性事件,所以我们要改成这样

    image.png

    最后附上整个代码,直接复制就可以用

    
    object LiveDataBus {
    
    //    LiveDataBus.with<String>("TestLiveDataBus").postStickyData("测试!")
    //    LiveDataBus.with<String>("TestLiveDataBus") .observerSticky(this, false) {
    //
    //    }
    
        private val mStickyMap = ConcurrentHashMap<String, StickyLiveData<*>>()
    
        fun <T> with(eventName: String): StickyLiveData<T> {
            var stickyLiveData = mStickyMap[eventName]
            if (stickyLiveData == null) {
                stickyLiveData = StickyLiveData<T>(eventName)
                mStickyMap[eventName] = stickyLiveData
            }
    
            return stickyLiveData as StickyLiveData<T>
        }
    
    
        /**
         * 将发射出去的LiveData包装一下,再做一些数据保存
         */
        class StickyLiveData<T>(private var eventName: String) : LiveData<T>() {
    
            var mLiveDataVersion = 0
            var mStickyData: T? = null
    
            fun setStickyData(stickyData: T) {
                mStickyData = stickyData
                setValue(stickyData)
            }
    
            fun postStickyData(stickyData: T) {
                mStickyData = stickyData
                postValue(stickyData)
            }
    
            override fun setValue(value: T) {
                mLiveDataVersion++
                super.setValue(value)
            }
    
            override fun postValue(value: T) {
                super.postValue(value)
            }
    
            fun observerSticky(owner: LifecycleOwner, sticky: Boolean, observer: Observer<in T>) {
                // 移除自己保存的StickyLiveData
                owner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
                    if (event == Lifecycle.Event.ON_DESTROY) {
                        mStickyMap.remove(eventName)
                    }
                })
    
                super.observe(owner, StickyObserver(this, sticky, observer))
            }
    
            /**
             * 重写LiveData的observer,把传入的observer包装一下
             */
            override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
                observerSticky(owner,false, observer)
            }
        }
    
        class StickyObserver<T>(
            private val stickyLiveData: StickyLiveData<T>,
            private val sticky: Boolean,
            private val observer: Observer<in T>
        ) : Observer<T> {
    
            /**
             * 打个比方:
             * 一条数据,名称为TestName,
             *      对应一个 StickyLiveData, 也就对应一个version, 初始的值为0,且这个可以复用
             *      且会创建StickyObserver,对应一个 mLastVersion, 初始的值为0
             *
             * 如果 StickyLiveData#version 和 StickyObserver#mLastVersion 没有对齐
             *      LastVersion < version --> 直接发送数据,就会产生黏性事件
             *
             * 源码就是这样没对齐,所以无法控制黏性事件
             *
             * 因为源码的流程
             *      将传入的observer包装成LifecycleBoundObserver(继承ObserverWrapper)会将传入的observer做保存和保存在hashMap
             *      最后在considerNotify遍历hashMap,活跃的观察者会调用observer.onChanged(t)去发送数据
             *
             * 所以这里把传入的observer包装成StickyObserver 进入源码后 --> 再变成LifecycleBoundObserver
             * 所以最终发送数据会调用StickyObserver的onChanged 就可以做黏性事件的处理了
             *
             */
            private var mLastVersion = stickyLiveData.mLiveDataVersion
    
            override fun onChanged(t: T) {
    
                if (mLastVersion >= stickyLiveData.mLiveDataVersion) {
                    if (sticky && stickyLiveData.mStickyData != null) {
                        observer.onChanged(stickyLiveData.mStickyData)
                    }
                    return
                }
                observer.onChanged(t)
            }
        }
    
    
    }
    
    
    

    相关文章

      网友评论

          本文标题:Android不使用反射,完成LiveDataBus

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