前言
大家好酝静,我是小益节榜!使用Jetpack全家桶的同學(xué)相信對LiveData都不陌生,其可以在很大程度上避免內(nèi)存泄漏别智、更好的將View層與Model層分離等諸多優(yōu)點使得LiveData在MVVM模式中開發(fā)成為不可或缺的利器宗苍。今天我們就將LiveData剖開來瞧瞧,為何它這么香薄榛!
推薦
文章將率先在公眾號「碼途有道」上發(fā)布讳窟,歡迎大家關(guān)注!
一敞恋、LiveData的常用方法
LiveData主要是基于觀察者機制實現(xiàn)的丽啡,LiveData是被觀察者,其觀察者是Observer硬猫,當(dāng)LiveData有數(shù)據(jù)變動時會通知它的觀察者去更新數(shù)據(jù)补箍。LiveData常用的幾個方法如下:
- setVaule
- postValue
- observe
- observeForever
二、setValue
setVaule與postVaule都是用來修改LiveData的值的啸蜜,我們先看setValue的源碼:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
在上述代碼中有一個@MainThread
注解坑雅,表示setValue只能在主線程中調(diào)用,并且在方法開頭還有一句assertMainThread("setValue")
來判斷當(dāng)前調(diào)用是否是在主線程中進行衬横,如果不是在主線程則會拋出異常裹粤。
mVersion++
用于記錄LiveData是否有更新,每有一次更新蜂林,mVersion都會加一蛹尝,在后續(xù)會使用到后豫。
mData = value
非常好理解,只是簡單的記錄需要更新的值突那。
dispatchingValue(null)
用于通知觀察者更新數(shù)據(jù)挫酿,源碼如下:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>,
ObserverWrapper>> iterator = mObservers.iteratorWithAdditions();
iterator.hasNext();
) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
dispatchingValue(@Nullable ObserverWrapper initiator)
傳入的參數(shù)是觀察者,如果有觀察者傳入愕难,只通知這個傳入的觀察者進行數(shù)據(jù)更新早龟,否則會遍歷該LiveData下所有的觀察者,并一一通知更新猫缭。在上述代碼中真正去通知觀察者進行數(shù)據(jù)更新的是considerNotify()
方法葱弟,源碼如下:
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
源碼中的流程非常簡單:
- 首先通過觀察者的
mActive
屬性判斷是否處于活躍狀態(tài);如果活躍繼續(xù)往下走猜丹,否則到此結(jié)束芝加。 - 之后通過觀察者的
shouldBeActive()
方法判斷其所在頁面是否處于活躍狀態(tài)(比如觀察者所在的頁面已經(jīng)走到onDestory函數(shù),那么頁面就不是處于活躍狀態(tài)),如不處于活躍狀態(tài)則需要將觀察者自身的狀態(tài)修改為非活躍狀態(tài)射窒。 - 如處于活躍狀態(tài)藏杖,再通過將觀察者自己的
mLastVersion
與LiveData的mVersion
進行對比,若mLastVersion >= mVersion
則代表沒有更新脉顿,否則就是有更新蝌麸。 - 最后,若有更新艾疟,則觀察者會修改自己的
mLastVersion
并調(diào)用onChanged()
方法做數(shù)據(jù)更新處理来吩。
三、postValue
static final Object NOT_SET = new Object();
volatile Object mPendingData = NOT_SET;
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
上面是postValue的相關(guān)源碼蔽莱,我們先理一下邏輯:mPendingData
的初始值是NOT_SET
弟疆,每當(dāng)有更新時,mPendingData
會記錄新的value盗冷,之后post一個Runnable交給主線程處理兽间,Runnable內(nèi)部會調(diào)用setValue來更新數(shù)據(jù),并且將mPendingData
的值重新置為NOT_SET
正塌。
postValue與setValue相比,postValue可以在任意線程中調(diào)用恤溶,而setValue只能在主線程中調(diào)用乓诽,但是postValue內(nèi)部最終還是通過調(diào)用setValue來實現(xiàn)數(shù)據(jù)更新。
postValue有一點需要注意:多次調(diào)用postValue咒程,只有最后一次調(diào)用時傳入的值有效鸠天。因為在postValue源碼中,是通過mPendingData
來記錄需要更新的值帐姻,并通過mPendingData == NOT_SET
來決定是否需要更新稠集;但在更新未結(jié)束前奶段,mPendingData
不等于NOT_SET
,即不能提交新的Runnable剥纷,而mPendingData
的值卻可以被更新痹籍,所以更新時獲取的就是最后一次傳入的值。
四晦鞋、observer.shouldBeActive()
在上述提到的considerNotify()
方法中蹲缠,有一個shouldBeActive()
方法,此方法屬于觀察者悠垛,用于判斷觀察者所在頁面是否處于活躍狀態(tài)线定。而在LiveData中,共有兩種觀察者:LifecycleBoundObserver
與AlwaysActiveObserver
确买。
4.1 LifecycleBoundObserver與observe
LifecycleBoundObserver是帶有對所在頁面生命周期判斷的觀察者斤讥,與LiveData的observe()
方法聯(lián)用(observe()內(nèi)部調(diào)用的是LifecycleBoundObserver),源碼如下:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
......
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
......
}
在LifecycleBoundObserver的shouldBeActive()
方法中湾趾,會判斷頁面至少要處于STARTED
狀態(tài)才認為是處于活躍狀態(tài)芭商,即當(dāng)Activity處于onStart()與onPause()之間則認為處于活躍狀態(tài)。以下是狀態(tài)源碼:
public enum State {
// onDestroy()
DESTROYED,
INITIALIZED,
// 介于 onCreate() -- onStop() 之間
CREATED,
// 介于 onStart() -- onPause() 之間
STARTED,
// onResume()
RESUMED;
public boolean isAtLeast(@NonNull State state) {
}
}
綜上可得撑帖,正因為LifecycleBoundObserver中shouldBeActive()
方法的實現(xiàn)蓉坎,才使得LiveData具有可以避免內(nèi)存泄漏的能力。
4.2 AlwaysActiveObserver與observeForever
AlwaysActiveObserver作為LiveData中的另一種觀察者胡嘿,與observeForever()
方法聯(lián)用(observeForever()內(nèi)部調(diào)用的是AlwaysActiveObserver)蛉艾,其shouldBeActive()
直接返回true,源碼如下:
private class AlwaysActiveObserver extends ObserverWrapper {
......
@Override
boolean shouldBeActive() {
return true;
}
}
如此一來衷敌,使用observeForever()
方法進行訂閱后勿侯,便沒有了對當(dāng)前頁面進行生命周期判斷的能力;每當(dāng)有數(shù)據(jù)變動時缴罗,都會通知觀察者進行更新處理助琐。使用此方法,需要注意內(nèi)存泄漏問題面氓。
五兵钮、小結(jié)
本章內(nèi)容主要講解LiveData的內(nèi)部觀察者機制,讓大家使用時更加了然于心舌界。LiveData除了作為MVVM模式中的重要一環(huán)之外掘譬,現(xiàn)在很多開發(fā)者還將其用作應(yīng)用內(nèi)的通信手段,后續(xù)文章我們將會介紹如何使用LiveData搭建通訊框架呻拌。