Android 官方提供的MVVM模式 ,有 DataBinding,ViewModel 和 LiveData組成,
廢話少說,先看下LiveData怎么用的?
class TestActivity : AppCompatActivity() {
private var data: MutableLiveData<String> = MutableLiveData()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
// 通過 observe LiveData 資料
data.observe(this, object : Observer<String> {
// 通過 observe 回呼 資料
override fun onChanged(t: String?) {
Timber.tag("MyTest").d(t)
}
})
button.setOnClickListener {
/**
* 通過 postValue / setValue 設定資料
* setValue() 必須在主執行緒
* postValue() 在哪個執行緒設定都可以 最侄訓是通過 setValue() 設定的
* */
data.postValue("postValue12345")
data.setValue("setValue12345")
}
}
}
LiveData 是一個抽象類,不能創建實體,那就用它的子類 MutableLiveData 來創建一個LiveData,
很明顯,這是一種觀察者模式,LiveData 通過 observe() 注冊監聽資料,通過setValue / postValue 設定資料,其實postValue() 最侄訓是通過 setValue() 設定的,用過的朋友相信都知道,
但是這篇文章,不是看下怎么使用,是探究一下 LiveData 原始碼,看它是怎么做到和宿主生命周期系結的,
好的,我們帶著 4 個問題去看原始碼:
【問題1】:如何做到伴隨宿主Activity 或Framgent 銷毀而銷毀,無需手動取消監?
【問題2】:如何做到只有在宿主Activity 或Framgent 可以見時,才把新資料發送給監聽者的?
【問題3】:如何做到在宿主Activity 或Framgent 不可見時設定資料,不會立馬把新資料發送給監聽者,等Activity 或Framgent 重新可見時再把新資料發送給監聽者?
【問題4】:如何做到在宿主Activity 或Framgent 重新可見時,只有在資料被重新更新了的情況下才去發送資料給觀察者,資料沒有被更新過不會通知監聽者
【-------------------Part1-----------------------】
首先,我們看下注冊監聽時做了些什么邏輯,看下 LiveData.observe() 的原始碼
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer){
// ---------------注釋1 ---------------
assertMainThread("observe");
// ---------------注釋2 ---------------
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
// 注釋3 這個是重點 大部分邏輯在這個 LifecycleBoundObserver 里面
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// ---------------注釋4 ---------------
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;
}
// ---------------注釋5 ---------------
owner.getLifecycle().addObserver(wrapper);
}
【注釋1】:檢測確保是在主執行緒監聽,否則會拋出例外,所以 LiveData 的監聽必須在主執行緒,有興趣的同學可以進去看一下,里面很簡單的代碼
【注釋2】: 如果當前宿主 LifecycleOwner ( 即 :Activity / Framgent) 已經是 destory 狀態,那就沒必要注冊監聽了,直接退出,這個邏輯無需解釋了
【注釋3】: 通過 LifecycleBoundObserver 把 LifecycleOwner 和 LiveData 的監聽者Observer 系結在一起,讓 LifecycleOwner 的生命周期 和 LiveData 的監聽者Observer聯動起來,具體怎么聯動法,等下再看,
【注釋4】: 把創建好的 LiveData 監聽者保存在 mObservers里面,之后有資料變化時,會遍歷 mObservers 的每個元素,把符合條件的監聽者逐個發新資料,
【注釋5】: LifecycleOwner 監聽生命周期,其生命周期狀態變化的回呼都在 LifecycleBoundObserver 回呼,
所以,這一部分總結一下,就是 LifecycleBoundObserver 把 LifecycleOwner 和 LiveData 的監聽者系結聯動起來,讓監聽者感知 Activity/Fragment的生命周期,
【-------------------Part2-----------------------】
我們就看上面所說道的 LifecycleBoundObserver 就可以了,看下這個 LifecycleBoundObserver 是怎么實作的
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
//省略無關緊要的代碼.....................
@Override
boolean shouldBeActive() {
// 這里的意思是只有在LifecycleOwner(Activity / Fragment) 可見時才會回傳 true
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
// ----------------注釋1---------------
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
// ----------------注釋2---------------
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
// ----------------注釋3---------------
activeStateChanged(shouldBeActive());
}
//省略無關緊要的代碼.....................
}
private abstract class ObserverWrapper {
//省略無關緊要的代碼.....................
void activeStateChanged(boolean newActive) {
// 狀態和之前一樣不執行,這個很合理
if (newActive == mActive) {
return;
}
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) {
// ----------------注釋4---------------
dispatchingValue(this);
}
}
}
省略了一些無關緊要的代碼,就看到 LifecycleBoundObserver 是集成于 ObserverWrapper 以及 實作了 LifecycleEventObserver 介面 ,
【注釋1】: 宿主 LifecycleOwner ( 即 :Activity / Framgent) 生命周期的變化,會通過注釋1這個 onStateChanged() 這個方法回呼,這個就是【Part1】注釋5 owner.getLifecycle().addObserver(wrapper) 的作用
【注釋2】:當宿主 LifecycleOwner ( 即 :Activity / Framgent)的生命周期是 destory 時,會把這個監聽者移除掉,這個【Part1】注釋4相對應,觀察者模式的監聽和取消,這個就是解釋了我們的【問題1】(如何做到伴隨宿主Activity 或Framgent 可以銷毀而銷毀,無需手動取消監的?)
【注釋3】:狀態變化最終呼叫 activeStateChanged() ,這個方法在 LifecycleBoundObserver 父類 ObserverWrapper 里面,這里面的邏輯看父類的代碼就清楚了,但是這里傳入了一個引數,引數通過 shouldBeActive() 獲得,里面的邏輯有興趣的同學可以自己進入看一下,就是只有在LifecycleOwner( 即 :Activity / Framgent) 可見時才會回傳 true,
【注釋4】:最終 dispatchingValue() 去通知監聽者,但是這里有個條件,就是這個方法的入參newActive是true時才會執行,很明顯,這個 newActive 就是注釋3傳入的,也就是 LifecycleOwner( 即 :Activity / Framgent)可見時才會為true,才會執行 dispatchingValue() 去通知監聽者,這個就是 【問題2】和 【問題3】,不可見不通知,重新可見再通知,
好了,到這里就是我們就很容易引出一個問題,當我們的 Activity / Framgent 每次重新可見時,都通知觀察者嗎?按理應該在資料有個變化才通知,沒有變化時沒必要通知的,這就是我們的問題【問題4】了,其實都是在上面所說的 dispatchingValue() 方法里
【-------------------Part3-----------------------】
好,我們看一下 dispatchingValue() 里面的邏輯
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
//--------注釋1 執行通知
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
//--------注釋2 執行通知
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// ----- 注釋3 當前 Version 是否已經發送過,發送過退出不需要發送
if (observer.mLastVersion >= mVersion) {
return;
}
// ----- 注釋4 保存當前 Version 表示當前資料已經發送給觀察者了
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
其實 dispatchingValue() 就是遍歷所有觀察者,把資料把資料發送給觀察者,主要看 【注釋1】和 【注釋2】即可,里面就是執行發送給觀察者,但是這一步還是沒看到我們【問題4】的答案,
我們再進入【注釋1】和【注釋2】進入的方法 considerNotify() 里面,可以看到【注釋3】和 【注釋4】,這就是判斷當前資料是不是已經發送過了,至于 mVersion 是什么時候設定的,搜一下參考即可看到是在 LiveData.setValue() 的時候設定,因為postValue() 最侄訓是通過 setValue() 設定的,所通過哪種方式設定資料,都會跑進 LiveData.setValue()來,
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
一目了然了吧,,,,,,,,,
所以【問題4】 整個流程是:每個 LiveDate 對應保存一個Version, LiveDate 每被設定一次資料,對應的 Version 會自增1,當這個資料被發送給觀察者后,這個 Version 會被存起來,當Activity 從不可見回到可見時,它會判斷存起來的 Version 和 LiveDate 的 Version 是不是一致,如果是一致就代表這個資料已經發送過給觀察者了,不會再次多余的發送一次,只有在不一致時,才會發新的資料發送給觀察者,這就是為什么 Activity / Fragment 就算多次從不可見回到可見時,都只會發送一次同樣的資料給觀察者,這就是我們所要找的【問題4】的答案了,
以上代碼邏輯如有誤,請留言指出,謝謝
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/302536.html
標籤:其他
