目前關于LiveData源碼解讀的文章非常多了掸犬,本文就不重復了侈净,這里只對核心流程做解讀。關于源碼流程抹腿,推薦:Android livedata 源碼解剖
系列文章
Android Jetpack ViewModel解析
Android Jetpack LiveData解析
Android Jetpack DataBinding原理淺析(簡版)
本文主要解決如下幾個問題:
1晕鹊、LiveData是如何關聯生命周期的松却?
2、LiveData的發(fā)送事件溅话、接收事件原理
3玻褪、為什么LiveData可以先發(fā)射數據再注冊?類似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
等。在執(zhí)行生命周期方法的時候更新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狀態(tài)易核。注意:STATE 為STARTED/RESUMED
就是說生命周期的方法為ononStart()
匈织、onResume()
、onPause()
時都表示active,這3個狀態(tài)都可以接收數據更新呻纹。網上很多說只有onstart和onresume才是活躍狀態(tài)的應該都是沒有驗證過的缀踪。
onStateChanged
是GenericLifecycleObserver接口的方法,當生命周期變化的時候會回調它弦追。這里會做判斷,如果是已經destroy花竞,直接移除觀察者劲件;否則會調用 activeStateChanged 方法。
到這里约急,問題1--關聯生命周期就講清楚了零远。
二、LiveData的發(fā)送事件厌蔽、接收事件原理
LiveData發(fā)送事件有2個方法:setValue()和postValue()牵辣,其中setValue()
方法只能在主線程發(fā),而postValue()
方法可以在子線程發(fā)奴饮,Observer的onChange()
始終在主線程纬向。
setValue
只要有出于active狀態(tài)的觀察者,這個方法就會被數據發(fā)送給它們戴卜。這里的關鍵是dispatchingValue(null);
按照上面的調用可以看出逾条,當參數為 null 的時候,遍歷所有的 obsever投剥,最后通過調用considerNotify()
進行分發(fā)师脂。
這里會做一些判斷,只有出于活躍狀態(tài)且數據是數據是最新的江锨,才會去分發(fā)數據吃警,最后回調到我們熟悉的onChanged()
。
postValue
這個方法是可以在子線程中發(fā)數據的啄育,但是我們最后的onChanged()
方法卻始終在主線程的汤徽,這是怎么做到的呢?答案也很簡單灸撰,就在postToMainThread()
方法谒府,具體是在DefaultTaskExecutor#postToMainThread
創(chuàng)建一個主線程的handler把任務發(fā)到主線程拼坎,最后還是調用setValue()
。
三完疫、為什么LiveData可以先發(fā)射數據再注冊泰鸡?類似EventBus的粘性消息
我們都知道LiveData在發(fā)射數據的時候,如果Activity出于inactive狀態(tài)時是接受不到消息的壳鹤,而是等變成active狀態(tài)時才能接受盛龄。而且還能實現類似EventBus的粘性消息,比如在A頁面發(fā)射數據芳誓,然后打開B頁面余舶,在B頁面注冊觀察者,同樣能接收到數據锹淌。它的原理其實不復雜的匿值,下面一起來看看:
在方法內部首先會保存要發(fā)射的數據,然后調用dispatchingValue
分發(fā)數據赂摆,這個方法最后會調用considerNotify()
方法
considerNotify()
方法會先判斷觀察者是否處于active狀態(tài)挟憔,只有出于活躍狀態(tài)的觀察者才能收到消息。那為什么頁面從后臺切換到可見狀態(tài)也就是active時又能接收到之前發(fā)射的數據呢烟号?
原因很簡單绊谭,因為LiveData內部關聯了生命周期相關的方法,當生命周期變化的時候都會回調
onStateChanged()
方法汪拥,在這里面會去調用activeStateChanged()
,而它最后會調用considerNotify()
方法去分發(fā)消息达传。而粘性消息也是這個原理。
四迫筑、LiveData如何保證不會內存泄漏的宪赶?
在一開始的observe()
方法中會把Activity中創(chuàng)建的Observer對象添加到一個Map集合中,最后當生命周期方法執(zhí)行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引用了疯潭,這樣就不會發(fā)生內存泄漏的情況了赊堪。
總結
最后借用 可被感知的數據 - LiveData 原理詳解一張圖來總結LiveData原理