LiveData 源碼解析
之前做過一篇關(guān)于Lifecycle的源碼解析,里面分析了
- 生命周期擁有者如何進行生命周期的感知(通過Fragment)
- 當(dāng)生命周期變化時,如何進行進行通知:將Obsever進行包裝竿滨,生成LifecycleEventObserver的具體實現(xiàn)來,然后在生命周期變化時涕癣,調(diào)用其對應(yīng)的狀態(tài)的分發(fā)彬祖。
在通常進行使用的過程中,我們都是將數(shù)據(jù)通過 LiveData 進行一層包裝纽竣,然后就可以進行其數(shù)據(jù)的變化監(jiān)聽了墓贿,那么其具體是如何實現(xiàn)的呢茧泪?
慣例,先來個簡單的測試demo
object SplashViewModel{
var logined = MutableLiveData<Boolean>()
init {
logined.postValue(true)
}
}
class SplashActivity : BaseBindingActivity<ActivitySplashBinding, SplashViewModel>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
SplashViewModel.logined.observe(this, Observer { print(it)})
}
}
只需要一個簡單的 observe() 方法聋袋,就可以實現(xiàn)生命周期的監(jiān)聽队伟,然后將數(shù)據(jù)發(fā)送到我們的Activity中,我們看看這個方法里面到底做了什么
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// 頁面銷毀幽勒,直接返回
return;
}
//包裝
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
//如果已經(jīng)存在嗜侮,拋異常
throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
}
if (existing != null) {
return;
}
//增加一個監(jiān)聽者
owner.getLifecycle().addObserver(wrapper);
}
可以看到,只是將我們的生命周期擁有者和監(jiān)聽者進行了一次包裝啥容,生成了 LifecycleBoundObserver 類锈颗,然后將它添加到監(jiān)聽者列表中。
在之前的Lifecycle的源碼解析文章中咪惠,我們了解到击吱,當(dāng)頁面發(fā)生變化時,會調(diào)用監(jiān)聽者的 onStateChanged() 方法遥昧。
@Override
boolean shouldBeActive() {//判斷當(dāng)前頁面是否屬于激活狀態(tài)(即可見狀態(tài))
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//如果頁面銷毀了覆醇,則直接移除當(dāng)前對應(yīng)的監(jiān)聽者
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//進行狀態(tài)的變更
activeStateChanged(shouldBeActive());
}
所以當(dāng)界面的生命周期變化時,會調(diào)用 activeStateChanged() 來進行狀態(tài)的變更處理
//進行狀態(tài)的轉(zhuǎn)變
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
//LiveData的激活的觀察者數(shù)量進行變化
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
//原來沒有激活的觀察者炭臭,現(xiàn)在有了新增的
// 說明LiveData從無激活的觀察者->有激活的觀察者
onActive();//留下鉤子永脓,給繼承者使用
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
//當(dāng)前頁面未激活,并且變化后徽缚,LiveData中處于激活狀態(tài)的觀察者數(shù)量為0憨奸,
// 說明LiveData從有激活的觀察者->無激活的觀察者
onInactive();//留下鉤子,給繼承者使用
}
if (mActive) {//如果頁面變化為了激活狀態(tài)凿试,那么進行數(shù)據(jù)的分發(fā)
dispatchingValue(this);
}
}
}
這里主要根據(jù)頁面的激活數(shù)排宰,預(yù)留了兩個鉤子函數(shù),用戶可以做一些自己的數(shù)據(jù)處理那婉。最主要的還是 dispatchingValue() 中的數(shù)據(jù)處理板甘。
//分發(fā)數(shù)據(jù)
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
//如果正在分發(fā),則將mDispatchInvalidated置為true详炬,那么在分發(fā)過程中盐类,會根據(jù)這個標(biāo)志位重新新數(shù)據(jù)的分發(fā)
mDispatchInvalidated = true;
return;
}
//標(biāo)記正在進行數(shù)據(jù)的分發(fā)
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {//如果有對應(yīng)的監(jiān)聽者,直接分發(fā)給對應(yīng)的監(jiān)聽者
considerNotify(initiator);
initiator = null;
} else {
//遍歷所有的觀察者呛谜,然后進行數(shù)據(jù)的分發(fā)在跳,
// 如果分發(fā)過程中,發(fā)現(xiàn)mDispatchInvalidated變化了隐岛,那么說明有新的數(shù)據(jù)變更猫妙,則退出當(dāng)前混選,然后從新分發(fā)新的數(shù)據(jù)
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
//通知某個觀察者進行了數(shù)據(jù)的變化
private void considerNotify(ObserverWrapper observer) {
//觀察者未激活聚凹,返回
if (!observer.mActive) {
return;
}
//觀察者當(dāng)前狀態(tài)為激活割坠,但是當(dāng)前變?yōu)榱瞬豢梢姞顟B(tài)齐帚,那么調(diào)用
//activeStateChanged方法
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//如果數(shù)據(jù)版本已經(jīng)是最新的了,那么直接返回
if (observer.mLastVersion >= mVersion) {
return;
}
//修改數(shù)據(jù)版本號
observer.mLastVersion = mVersion;
//調(diào)用監(jiān)聽者的onChanged方法
observer.mObserver.onChanged((T) mData);
}
在數(shù)據(jù)分發(fā)過程中彼哼,根據(jù)相應(yīng)的觀察者數(shù)據(jù)版本號对妄,然后和當(dāng)前的數(shù)據(jù)的版本號進行比較,如果是新的數(shù)據(jù)敢朱,那么調(diào)用觀察者的 onChange()方法剪菱,也就是我們在開始時寫的測試demo中的 print(it) 。
總結(jié)一下頁面發(fā)生變化時拴签,數(shù)據(jù)的處理流程:
- 當(dāng)頁面發(fā)生變化琅豆,從不可見變?yōu)榭梢姇r,會將LiveData中的數(shù)據(jù)版本號跟對應(yīng)的觀察者中的版本號進行比較篓吁,如果大,則調(diào)用onChanged()進行數(shù)據(jù)的回調(diào)蚪拦。
- 如果頁面為不可見杖剪,那么不會進行數(shù)據(jù)的回調(diào)處理。
那么當(dāng)我們使用 setValue() 驰贷,或者 postValue() 時盛嘿,LiveData 又是做了什么處理呢?
我們先看看 setValue()
protected void setValue(T value) {
assertMainThread("setValue");
//記錄當(dāng)前數(shù)據(jù)的版本號
mVersion++;
//記錄設(shè)置的數(shù)據(jù)值
mData = value;
//進行數(shù)據(jù)的分發(fā)
dispatchingValue(null);
}
可以看到弓颈,直接將數(shù)據(jù)版本號+1渣玲,然后進行了數(shù)據(jù)的分發(fā)贮折,dispatchingValue() 我們剛才進行過分析,如果參數(shù)為null芥炭,那么會遍歷所有的監(jiān)聽者,逐個通知所有觀察者進行了數(shù)據(jù)的變化(前提是觀察者處于激活狀態(tài))恃慧。
我們再看看 postValue()
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
//通過線程池分發(fā)到主線程去處理
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() 通過線程池技術(shù),將數(shù)據(jù)在主線程進行了 setValue()痢士。
匯總
1.當(dāng)生命周期不可見時彪薛,會將最新的數(shù)據(jù)保存在LiveData中,然后保存相應(yīng)的版本號怠蹂,當(dāng)其可見時善延,會將數(shù)據(jù)變化通知
2.當(dāng)LiveData中的數(shù)據(jù)變化時,會遍歷所有的監(jiān)聽頁面城侧,然后進行數(shù)據(jù)的變化通知易遣。
附帶一張ObserverWrapper
的結(jié)構(gòu)圖
本文由博客一文多發(fā)平臺 OpenWrite 發(fā)布!