本篇文章用到了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();
运行之后的结果:
前两条很清楚是通过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只能在主线程注册观察者
上面图片第二句的意思是如果页面已经销毁就不能注册
这两句很重要,第一句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 super T> 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方法的片段
existing很显然是先通过observer这个key查询Map中有没有,有就返回已经保存的对应的value没有才去put进map中,这个existing是我们的LifecycleBoundObserver的实例,existing.isAttachedTo(owner)方法的实现一定是ObserverWrapper的子类也就是我们的LifecycleBoundObserver,再返回到我们LifecycleBoundObserver的源码现在就知道这其中一个方法isAttachedTo有啥作用了
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
继续分析:
上面setValue中的第一句assertMainThread方法是用来检查setValue是不是在主线程中调用的如果不是就会直接抛出异常,最终调用dispatchingValue方法且参数是null
继续:
这里就开始上难度了:
看到了在循环一个名字为mObservers的Map类型的成员变量,然后又把这个mObservers的每一个元素的value传到了considerNotify这个方法。这个循环的体现就是如果一个livedata注册了很多歌observer那每次set一次都会通知到所有观察者
先看mObserverMap是什么:
哈哈果然不出所料,在取ObserverWrapper了其实取得是ObserverWrapper的子类LifecycleBoundObserver
继续往下看:
正常情况下会调用到最后一句,很清楚和我们想的一样,observer是LifecycleBoundObserver,mObserver是我们注册的时候传进去的观察者,调用观察者的onChanged方法这样就实现了注册然后通过setValue通知到观察者的整个流程。这真是典型的观察者模式
好了一切都归于,等等我们提出的问题才解决到了2.
3.LiveData为什么能够有效避免内存泄漏
首先我们知道了观察者的维护类LifecycleBoundObserver有观察生命周期的能力,所以肯定是他顶住劲了
果然不出所料,这一句代码有效的处理了内存泄漏的问题,在生命周期变化的时候一定会调用onStateChanged方法,在里面进行判断如果是页面销毁就把观察者的注册解除。这给了我们处理内存泄漏很好的例子
4.LiveData的粘性怎么体现,为什么会有粘性,为什么只会对最后一次的数据产生粘性
粘性的体现在我第一个放出的例子中就有体现,同一个liveData在setValue后又注册了一个观察者,这时就会立即触发一次观察者的onChanged方法。
为什么会有粘性:
上面分析过了,当我们给LiveData注册观察者执行observe方法,obsere方法的最后一句是
所以LifecycleBoundObserver就具备了观察owner生命周期的能力:
这个shoudlBeActive()方法就是判断宿主是否处于大于STARTED状态
然后我们具体看activeStateChanged方法
mActive一看就是LifecycleBoundObserver内部维护的一个宿主是否活跃的状态(是否处于大于STARTED状态),首先弄清楚mActive是怎么维护的如下图
初始化的时候默认是false,只在下图这里进行了赋值同步
注意这个判断:
这个判断的意思是只有在LifecycleBoundObserver内部维护的状态mActive和当前owner的状态不一致时才会跳过判断继续往下走
然后在mActive为true的时候调用了dispatchingValue(this),
又回到了considerNotify方法,这次仔细分析一下:
第一个判断:
observer是LifecycleBoundObserver我们的观察者,如果我们观察者内维护的mActive是false就直接return,意思是如果观察者认为现在的宿主不是活跃状态那就不进行通知
这个感觉是一个保险工作,看注释就好,是对宿主当前的状态再次进行了判断然后又走了一次上面的流程
继续看:
先搞清楚observer.mLastVersion是观察者维护的一个版本号和mActive有点类似:
在创建观察者的时候初始化赋值是-1
说这这么多,我们回到主题粘性是怎么产生的,在setValue之后,再注册观察者的时候这时
mActive和mLastVersion都是初始值fase和-1,注册完后随着owner生命周期的变化或者直接就已经是active状态的,
mActive那层拦截就会通过:
而初始的mLastVersion是-1,而mVersion在setValue的时候加1了
所以这层判断就拦不住了:
所以在setValue之后只要一注册观察者立刻就执行了一次onChanged方法
现在想想,就算没有setValue在注册的时候也会走到这里,只不过被这个mLastVersion和mVersion的判断拦住了,mVersion在没有setValue的时候也是-1
还有一个小问题那为什么只会对最后一次的数据产生粘性?
很简单在setValue方法执行后注册的观察者,最后会调用这句代码
mData是啥就会直接给onChanged方法传过去,那看一下mData是啥吧:
就是在LiveData中维护的一个成员变量,它保存的就是setValue的值,所以只有最后一条setValue的数据产生了粘性
好了一切归于平静了。
总结一下:其实就是一个典型的观察者,和Lifecycle结合了,有几个巧妙的判断,造就了能观察生命周期的LiveData
如何去除粘性呢?
下一篇:LiveData去除粘性