JetPack作為Google官方推薦的一套標準化開發(fā)套件,很值得去使用和學(xué)習(xí)酬荞。
這篇介紹LiveData
。LiveData
是一種可觀察的數(shù)據(jù)存儲器類瞧哟。與常規(guī)的可觀察類不同混巧,LiveData
具有生命周期感知能力,意指它遵循其他應(yīng)用組件(如 Activity勤揩、Fragment 或 Service)的生命周期咧党。這種感知能力可確保 LiveData
僅更新處于活躍生命周期狀態(tài)的應(yīng)用組件觀察者。
基本使用
LiveData
本質(zhì)是一個①遵循生命周期陨亡、②可供觀察的存儲類凿傅。
使用姿勢1 | 使用姿勢2 |
---|---|
正常使用.png
|
黏性使用.png
|
乍一看和我們之前學(xué)的EventBus
、RxBus
之類的事件總線很像数苫,不就是個觀察者模式嘛。姿勢2不就是反映出黏性的狀態(tài)嘛辨液。
事實也是如此虐急。
不過它具有生命周期感知能力,LiveData
只會將更新通知給活躍的觀察者滔迈。為觀察 LiveData
對象而注冊的非活躍觀察者不會收到更改通知止吁。
Google官方不建議我們這樣直接在Activity中使用,而是將
LiveData
放在ViewModle
中燎悍,Activity中只負責(zé)監(jiān)聽及變化后的處理事件敬惦。以構(gòu)建成MVVM架構(gòu)。
源碼解析
MutableLiveData
繼承自LiveData
谈山,直接看LiveData
的observe()
方法俄删。
observe(owner,observer)
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
之前說過,LiveData
僅更新處于活躍生命周期狀態(tài)的應(yīng)用組件觀察者奏路,這里的活躍狀態(tài)具體指的是START
和RESUME
畴椰。
首先是必須要在主線程執(zhí)行,判斷生命周期狀態(tài)是否活躍鸽粉;然后new一個LifecycleBoundObserver
命名為wrapper
斜脂,將其作為VALUE,以傳進來的observer
為KEY,存入mObservers
中触机。
然后將wrapper
放入生命周期的監(jiān)聽中帚戳。wrapper實現(xiàn)了LifecycleEventObserver
接口玷或,所以wrapper
放進去后接著就會調(diào)用wrapper
中的onStateChanged
方法【這一句內(nèi)容屬于Lifecycle
知識點,詳見Lifecycle解析】片任。
wrapper.onStateChanged
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
判斷了下生命周期是否活躍偏友,然后走向了activeStateChanged( )
。
這里傳入的布爾值是判斷生命周期狀態(tài):當(dāng)前狀態(tài)在STARTED
之前蚂踊,false; 在STARTED
狀態(tài)之后约谈,true。
說明只有在STARTED
和RESUME
狀態(tài)時會傳true進去犁钟,印證了之前說的 “活躍狀態(tài)具體指的是START
和RESUME
”棱诱。
//這個方法是在抽象類`ObserverWrapper`中。
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}
這個方法中涝动,先將傳進來的newActive
賦值給mActive
迈勋。
mActiveCount
表示活躍狀態(tài)下 obs的數(shù)量;wasInactive
(為true)表示之前活躍狀態(tài)下沒有obs;
mActive
true表示當(dāng)下處于活躍狀態(tài)醋粟,并且你傳給了我個obs靡菇。
所以mActive
為true的時候,mActiveCount
要+1米愿;為false時厦凤,mActiveCount
要-1。注意這里mActiveCount
發(fā)生了改變S丁较鼓!
然后判斷,如果改變之前沒有obs活躍 && 傳來的obs即將變活躍违柏,那就要onActive()
;
如果 改變之后依然沒有obs活躍 && 傳來的obs也不會變活躍博烂,那就onInactive()
;
當(dāng)然這兩個方法都是空的,需要用戶自己去寫漱竖。
說人話就是:當(dāng)活躍的數(shù)量0-->1時禽篱,執(zhí)行onActive()
;由1-->0時馍惹,執(zhí)行onInactive()
躺率。
最重要的其實是下一句:如果現(xiàn)在是活躍狀態(tài),我收到了obs讼积,所以要執(zhí)行下一步操作了肥照。
dispatchingValue(wrapper)
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;
}
這兩個布爾值,emmm勤众,看的有點繞舆绎。再看這個do while,這循環(huán)怎么這么怪?
//第一次A,B = false
if(A){
B = true;
return
}
A = true
do{
B = false
...//不會改變B的代碼
}while(B)
WTF??一臉黑人問號们颜?這種循環(huán)能跑到第二圈吕朵?這種循環(huán)要是能循起來猎醇,我當(dāng)場把顯示器吃掉!努溃!
不管了硫嘶,重點看do while中的代碼,傳進來wrapper是不為空的梧税,走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;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
一些列判斷之后,如果未被return第队,則執(zhí)行wrapper.mObserver.onChanged()
方法哮塞。
當(dāng)然,第一次
observer.mLastVersion
和mVersion
都是初始值-1凳谦,所以不會執(zhí)行到此忆畅。除非mVersion
變了...
大的流程走通了,再看看setValue方法尸执。
setValue
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
版本++家凯,存儲data,然后再dispatchingValue(null);
如失。
等等绊诲,這里也進到了dispatchingValue
,也就是說dispatchingValue
中可能出現(xiàn)多個線程同時訪問進去的情況褪贵。這樣一來之前看不懂的那兩個布爾值和一個長得奇怪的do while循環(huán)就說得過去了驯镊。
這種情況下,循環(huán)就循環(huán)起來了竭鞍。
咳咳,我們繼續(xù)??橄镜。dispatchingValue
方法中有一個針對null的判斷偎快,這時候傳進來的initiator為空,走else的方法洽胶。把mObservers
遍歷一遍晒夹,然后依次執(zhí)行considerNotify(iterator.next().getValue());
。
如果大家記性不太好的話姊氓,我?guī)痛蠹一貞浺幌拢?/p>
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
所以getValue方法中得到的就是我們在observe方法中初始化的wrapper丐怯。
再看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;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
這次進入這個方法的時候有一點不一樣,我們在setValue方法中版本++了翔横,所以這個時候mVersion大于mLastVersion了读跷,這個時候才會執(zhí)行observer.onChanged
方法。
mVersion
的意義就在這里體現(xiàn)出來了禾唁。
如果你先setValue(版本++),然后再observer()效览,onChanged
依然會被觸發(fā)无切。這就是所謂的黏性事件。也就是說黏性是在源碼中寫死了的丐枉,不支持像EventBus那般可進行配置哆键。你想不黏性都不行。
postValue
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() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
postValue也一樣瘦锹,通過一個mPostValueRunnable
籍嘹,最后轉(zhuǎn)到了SetValue方法。
總結(jié)
LiveData
的作用其實是事件的分發(fā)弯院,其實現(xiàn)原理是基于發(fā)布/訂閱者模式辱士,但是LiveData和傳統(tǒng)的EventBus、RxBus這類事件總線又不太一樣抽兆。
Google對其在功能上加以限制识补,幾乎只有set/post和observe這三個方法;而上述Bus框架理論上可以在代碼的任意一處進行分發(fā)辫红,在代碼的其他地方進行任意調(diào)用凭涂,雖然靈活,但無形中增加了管理成本贴妻,尤其是當(dāng)項目日益龐大的時候切油,若項目中的Bus管理不善,發(fā)送和接收的事件(event)將會泛濫成災(zāi)名惩,造成不可預(yù)期的后果澎胡。
而LiveData,可以通過和ViewModle的配合娩鹉,完美規(guī)避這些問題攻谁,使事件的傳遞更加純粹 和 易于管理。
同時弯予,LiveData
的生命周期感知能力也避免了由于生命周期的變化帶來的內(nèi)存泄露等問題戚宦。
當(dāng)然,你也完全可以利用LiveData將其封裝成LiveDataBus锈嫩,實現(xiàn)相似的事件總線框架受楼,但是這有違Google的初衷,Google開發(fā)團隊的初衷是讓我們使用LiveData+ViewModle的模式來管理數(shù)據(jù)呼寸,這才是Google團隊認為的最佳做法艳汽。
最后,關(guān)于LiveData的粘性設(shè)計可能帶來的BUG和解決方案对雪,我會另開一篇文章詳談河狐,不在此贅述。