LiveData原理,源码分析,通俗易懂

本篇文章用到了Lifecycle,如果没有了解过Lifecycle原理的同学请点传送门:

Lifecycle原理,源码分析_Allence的博客-CSDN博客

大家在看这篇文章的时候最好自己也点开源码跟着一步一步看一看,这样印象深刻

        MutableLiveData liveData = new MutableLiveData<>();
        liveData.observe(this, new Observer() {
            @Override
            public void onChanged(String str) {
                Log.e("liveData",str);
            }
        });

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                liveData.postValue("a");
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                liveData.postValue("b");
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(19000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        liveData.observe(MainActivity.this, new Observer() {
                            @Override
                            public void onChanged(String str) {
                                Log.e("liveData",str);
                            }
                        });
                    }
                });
            }
        }).start();

运行之后的结果:

LiveData原理,源码分析,通俗易懂_第1张图片

前两条很清楚是通过post触发的,第三条为啥观察者一注册就自动调用了一次onChange 而且为啥打印的是b也就是最后一条post的数据其实这就是liveData的粘性我们后面分析

上面是最简单的LiveData的使用,有点像handler,LiveData作为一个被观察者在注册了观察者之后,在调用setValue或者postValue的时候会通知观察者调用观察者的onChanged方法,相比handler来说LiveData可以监听LifecycleOwner(Activity或Fragment)的生命周期,当LifecycleOwner生命周期结束的时候会取消观察者的注册,这样就可以有效的避免内存泄漏

那么问题来了:

1.LiveData是什么,有什么作用

2.LiveData具体是怎么做到调用setVaule或者postValue就能通知到观察者调用观察者的onChanged方法的

3.LiveData为什么能够有效避免内存泄漏

4.LiveData的粘性怎么体现,为什么会有粘性,为什么只会对最后一次的数据产生粘性

1.LiveData是什么,有什么作用

LiveData是一个抽象类,我们一般使用它的实现类MutableLiveData,作用:可以通过调用setVaule或者postValue就能通知到注册的观察者,是典型的观察者模式的一个应用

2.LiveData具体是怎么做到调用setVaule或者postValue就能通知到观察者调用观察者的onChanged方法的

上源码:

我们从最开始注册观察者开始分析:

下面分析observe方法的片段

这一句是判断是不是在主线程中执行的,如果不是就会抛出异常,意味着LiveData只能在主线程注册观察者 

LiveData原理,源码分析,通俗易懂_第2张图片

上面图片第二句的意思是如果页面已经销毁就不能注册

 这两句很重要,第一句new了一个把LifecycleOwner和我们创建的观察者当作构造的参数构造了一个LifecycleBoundObserver,第二句保存到了mObservers中不出意外这个肯定是个map,

果然是一个以我们创建的观察者类型为key,以ObserverWrapper为value的Map,这个ObserverWrapper想都不用想肯定是LifecycleBoundObserver的父类

截屏占不下了直接copy源码过来:

 class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

现在是看不出来这个LifecycleBoundObserver,有啥用,但是有感觉,首先它实现了LifecycleEventObserver的接口看过我上一片:Lifecycle原理的应该知道这是Lifecycle的观察者实现了这个借口后只要注册观察了Lifecycle那LifecycleBoundObserver就具备了观察生命周期的能力

,其次这个LifecycleBoundObserver持有LifecycleOwner又持有我们的观察者,还被Map保存起来了看过我上一篇写的Lifecycle的应该知道他们两个很相似,是典型的观察者模式,保存就是为了一会儿取出来去通知观察者的。

继续往下分析observe方法的片段

LiveData原理,源码分析,通俗易懂_第3张图片

existing很显然是先通过observer这个key查询Map中有没有,有就返回已经保存的对应的value没有才去put进map中,这个existing是我们的LifecycleBoundObserver的实例,existing.isAttachedTo(owner)方法的实现一定是ObserverWrapper的子类也就是我们的LifecycleBoundObserver,再返回到我们LifecycleBoundObserver的源码现在就知道这其中一个方法isAttachedTo有啥作用了

LiveData原理,源码分析,通俗易懂_第4张图片

mOwner是observer第上一次注册时的宿主,参数owner是这次注册时的宿主,如果两个宿主是同一个就返回true反之返回false

继续看我们的判断

如果两个宿主不一样返回的是false这样正好能符合判断条件走进判断内部,然后抛出了异常,说明什么,说明如果我们的observer观察者已经注册在一个LifecycleOwner宿主中了就不能在另一个宿主中执行livedata.observe方法来注册 否则就是会抛出异常,这个异常的提示也很清楚

下面继续走我们的observe方法的片段:

这个也很好理解,如果 observer观察者已经注册过了,就不能再注册

最后一句: 

这一句就是我们上面提到的,wrapper是LifecycleBoundObserver的实例,LifecycleBoundObserver实现了Lifecycle的观察者的接口具备了观察Lifecycle的能力,这里就是在注册观察Lifecycle,这样LifecycleBoundObserver就具备了观察owner生命周期的能力

好了现在observe的方法分析完了,但是还不能归于平静,现在我们知道了我们传入的观察者和宿主被封装到了LifecycleBoundObserver的实例中,并且把这个实例保存到了一个叫mObservers的Map里,根据我们学习Lifecycle的经验估计是等着通知观察者的时候用,并且制定了规则一个observer(liveData的观察者)不能在不同的宿主中调用observe方法注册否则抛异常,一个observer在同一个宿主中只能注册一次就算注册多次也会被return,最后LifecycleBoundObserver还具备了观察宿主生命周期的功能。

下面我们继续分析setValue,看注册完了之后具体是怎么通知到观察者的:

postValue是在子线程使用的它也是通过handler切换的线程最终还是调用的setValue方法,所以我们只分析setValue

我们一般调用的是LiveData的实现类MutableLiveData

LiveData原理,源码分析,通俗易懂_第5张图片

继续分析:

LiveData原理,源码分析,通俗易懂_第6张图片

上面setValue中的第一句assertMainThread方法是用来检查setValue是不是在主线程中调用的如果不是就会直接抛出异常,最终调用dispatchingValue方法且参数是null

继续:

LiveData原理,源码分析,通俗易懂_第7张图片

 这里就开始上难度了:

看到了在循环一个名字为mObservers的Map类型的成员变量,然后又把这个mObservers的每一个元素的value传到了considerNotify这个方法。这个循环的体现就是如果一个livedata注册了很多歌observer那每次set一次都会通知到所有观察者

先看mObserverMap是什么:

哈哈果然不出所料,在取ObserverWrapper了其实取得是ObserverWrapper的子类LifecycleBoundObserver

继续往下看:

LiveData原理,源码分析,通俗易懂_第8张图片

正常情况下会调用到最后一句,很清楚和我们想的一样,observer是LifecycleBoundObserver,mObserver是我们注册的时候传进去的观察者,调用观察者的onChanged方法这样就实现了注册然后通过setValue通知到观察者的整个流程。这真是典型的观察者模式

好了一切都归于,等等我们提出的问题才解决到了2.

3.LiveData为什么能够有效避免内存泄漏

首先我们知道了观察者的维护类LifecycleBoundObserver有观察生命周期的能力,所以肯定是他顶住劲了

LiveData原理,源码分析,通俗易懂_第9张图片

果然不出所料,这一句代码有效的处理了内存泄漏的问题,在生命周期变化的时候一定会调用onStateChanged方法,在里面进行判断如果是页面销毁就把观察者的注册解除。这给了我们处理内存泄漏很好的例子

4.LiveData的粘性怎么体现,为什么会有粘性,为什么只会对最后一次的数据产生粘性

粘性的体现在我第一个放出的例子中就有体现,同一个liveData在setValue后又注册了一个观察者,这时就会立即触发一次观察者的onChanged方法。

为什么会有粘性:

上面分析过了,当我们给LiveData注册观察者执行observe方法,obsere方法的最后一句是

所以LifecycleBoundObserver就具备了观察owner生命周期的能力:

LiveData原理,源码分析,通俗易懂_第10张图片 这个shoudlBeActive()方法就是判断宿主是否处于大于STARTED状态

然后我们具体看activeStateChanged方法

LiveData原理,源码分析,通俗易懂_第11张图片

mActive一看就是LifecycleBoundObserver内部维护的一个宿主是否活跃的状态(是否处于大于STARTED状态),首先弄清楚mActive是怎么维护的如下图

LiveData原理,源码分析,通俗易懂_第12张图片

初始化的时候默认是false,只在下图这里进行了赋值同步

LiveData原理,源码分析,通俗易懂_第13张图片

注意这个判断:

LiveData原理,源码分析,通俗易懂_第14张图片这个判断的意思是只有在LifecycleBoundObserver内部维护的状态mActive和当前owner的状态不一致时才会跳过判断继续往下走

然后在mActive为true的时候调用了dispatchingValue(this),LiveData原理,源码分析,通俗易懂_第15张图片

又回到了considerNotify方法,这次仔细分析一下:

LiveData原理,源码分析,通俗易懂_第16张图片

 第一个判断:

LiveData原理,源码分析,通俗易懂_第17张图片

 observer是LifecycleBoundObserver我们的观察者,如果我们观察者内维护的mActive是false就直接return,意思是如果观察者认为现在的宿主不是活跃状态那就不进行通知

LiveData原理,源码分析,通俗易懂_第18张图片

 这个感觉是一个保险工作,看注释就好,是对宿主当前的状态再次进行了判断然后又走了一次上面的流程

继续看:

先搞清楚observer.mLastVersion是观察者维护的一个版本号和mActive有点类似:

LiveData原理,源码分析,通俗易懂_第19张图片

在创建观察者的时候初始化赋值是-1

只在这里赋值同步了一下LiveData原理,源码分析,通俗易懂_第20张图片

说这这么多,我们回到主题粘性是怎么产生的,在setValue之后,再注册观察者的时候这时

mActive和mLastVersion都是初始值fase和-1,注册完后随着owner生命周期的变化或者直接就已经是active状态的,

mActive那层拦截就会通过:

LiveData原理,源码分析,通俗易懂_第21张图片 而初始的mLastVersion是-1,而mVersion在setValue的时候加1了

LiveData原理,源码分析,通俗易懂_第22张图片

 所以这层判断就拦不住了:

LiveData原理,源码分析,通俗易懂_第23张图片 所以在setValue之后只要一注册观察者立刻就执行了一次onChanged方法

现在想想,就算没有setValue在注册的时候也会走到这里,只不过被这个mLastVersion和mVersion的判断拦住了,mVersion在没有setValue的时候也是-1

还有一个小问题那为什么只会对最后一次的数据产生粘性?

很简单在setValue方法执行后注册的观察者,最后会调用这句代码

 mData是啥就会直接给onChanged方法传过去,那看一下mData是啥吧:

LiveData原理,源码分析,通俗易懂_第24张图片

就是在LiveData中维护的一个成员变量,它保存的就是setValue的值,所以只有最后一条setValue的数据产生了粘性 

 好了一切归于平静了。

总结一下:其实就是一个典型的观察者,和Lifecycle结合了,有几个巧妙的判断,造就了能观察生命周期的LiveData

如何去除粘性呢?

下一篇:LiveData去除粘性

你可能感兴趣的:(安卓进阶,android,java)