目前关于LiveData源码解读的文章非常多了,本文就不重复了,这里只对核心流程做解读。关于源码流程,推荐:Android livedata 源码解剖
系列文章
Android Jetpack ViewModel解析
Android Jetpack LiveData解析
Android Jetpack DataBinding原理浅析(简版)
本文主要解决如下几个问题:
1、LiveData是如何关联生命周期的?
2、LiveData的发送事件、接收事件原理
3、为什么LiveData可以先发射数据再注册?类似EventBus的粘性消息
4、LiveData如何保证不会内存泄漏的?
先看看LiveData的基本使用
MutableLiveData<String> mLiveData = mTestViewModel.getLiveData();
mLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
//更新UI
}
});
一、LiveData是如何关联生命周期的?
先来看一下观察者订阅的方法observe()
,第一参数是LifecycleOwner
,第二个参数是观察者,也是最后接收回调的地方。如果你看过Lifecycle的的话,你应该知道,
关于LifecycleOwner
通常第一个参数传入Activity/Fragment对象,原因是新版本(>26)的FragmentActivity
和Fragment
已经实现了LifecycleOwner接口,而且它们内部有一个LifecycleRegistry
来存放生命周期State
、Event
等。在执行生命周期方法的时候更新LifecycleRegistry里的生命周期State、Event,,并且通过handleLifecycleEvent()
方法来通知对应的观察者。
这个observe方法重点关注2点:
1、ObserverWrapper
:通过LifecycleBoundObserver把observer包装;
2、addObserver()
:把包装后的observer对象添加到一个Map中,然后当LifecycleOwner改变的时候就会收到通知。
LifecycleBoundObserver
这里的关键方法是onStateChanged
和shouldBeActive
shouldBeActive
这里是调用了lifecycle的方法,如果Lifecycle 的 STATE 为STARTED/RESUMED
则返回true,表示active状态。注意:STATE 为STARTED/RESUMED
就是说生命周期的方法为ononStart()
、onResume()
、onPause()
时都表示active,这3个状态都可以接收数据更新。网上很多说只有onstart和onresume才是活跃状态的应该都是没有验证过的。
onStateChanged
是GenericLifecycleObserver接口的方法,当生命周期变化的时候会回调它。这里会做判断,如果是已经destroy,直接移除观察者;否则会调用 activeStateChanged 方法。
到这里,问题1--关联生命周期就讲清楚了。
二、LiveData的发送事件、接收事件原理
LiveData发送事件有2个方法:setValue()和postValue(),其中setValue()
方法只能在主线程发,而postValue()
方法可以在子线程发,Observer的onChange()
始终在主线程。
setValue
只要有出于active状态的观察者,这个方法就会被数据发送给它们。这里的关键是dispatchingValue(null);
按照上面的调用可以看出,当参数为 null 的时候,遍历所有的 obsever,最后通过调用considerNotify()
进行分发。
这里会做一些判断,只有出于活跃状态且数据是数据是最新的,才会去分发数据,最后回调到我们熟悉的onChanged()
。
postValue
这个方法是可以在子线程中发数据的,但是我们最后的onChanged()
方法却始终在主线程的,这是怎么做到的呢?答案也很简单,就在postToMainThread()
方法,具体是在DefaultTaskExecutor#postToMainThread
创建一个主线程的handler把任务发到主线程,最后还是调用setValue()
。
三、为什么LiveData可以先发射数据再注册?类似EventBus的粘性消息
我们都知道LiveData在发射数据的时候,如果Activity出于inactive状态时是接受不到消息的,而是等变成active状态时才能接受。而且还能实现类似EventBus的粘性消息,比如在A页面发射数据,然后打开B页面,在B页面注册观察者,同样能接收到数据。它的原理其实不复杂的,下面一起来看看:
在方法内部首先会保存要发射的数据,然后调用dispatchingValue
分发数据,这个方法最后会调用considerNotify()
方法
considerNotify()
方法会先判断观察者是否处于active状态,只有出于活跃状态的观察者才能收到消息。那为什么页面从后台切换到可见状态也就是active时又能接收到之前发射的数据呢?
原因很简单,因为LiveData内部关联了生命周期相关的方法,当生命周期变化的时候都会回调
onStateChanged()
方法,在这里面会去调用activeStateChanged()
,而它最后会调用considerNotify()
方法去分发消息。而粘性消息也是这个原理。
四、LiveData如何保证不会内存泄漏的?
在一开始的observe()
方法中会把Activity中创建的Observer对象添加到一个Map集合中,最后当生命周期方法执行ondestory之后会移除观察者,这样就避免了内存泄漏。从这段源码可以看出,最后是通过调用LifecycleBoundObserver#detachObserver
方法来解绑观察者的。
你以为这样就完了?其实没完。我一开始看别人这样说的,就没去多想,后面仔细想想内存泄漏到本质觉得没有彻底搞清楚,于是有了下面的内容。
内存泄漏的本质是什么?
我所理解的是:当不再使用的对象被其它对象所引用,导致它无法被回收,就会造成内存泄漏。
下面来看看这里的引用关系:
MutableLiveData<String> mLiveData = mTestViewModel.getLiveData();
mLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
//更新UI
}
});
在使用的时候,observe方法第一个参数传入的是Activity/Fragment对象,这里Activity和LiveData是互相引用?这里是不完全对的,
我们可以看到第一个参数owner最终是传入到LiveData内部类LifecycleBoundObserver
中了,所以引用关系应该是
Activity<---->LiveData.LifecycleBoundObserver
,所以最好移除了observer对象的时候,就不再持有Activity引用了,这样就不会发生内存泄漏的情况了。
总结
最后借用 可被感知的数据 - LiveData 原理详解一张图来总结LiveData原理