LiveData是什么喇闸?
1.首先LiveData在用法上其實(shí)是與數(shù)據(jù)實(shí)體類是一樣的東西,它負(fù)責(zé)暫存數(shù)據(jù)。
2.其次LiveData其實(shí)也是一個(gè)觀察者模式的數(shù)據(jù)實(shí)體類,它可以跟它注冊(cè)的觀察者回調(diào)數(shù)據(jù)是否已經(jīng)更新,比如以前的接口回調(diào)通知可以用LiveData做到躏救。
3.LiveData還能知曉它綁定的Activity或者Fragment的生命周期,它只會(huì)給前臺(tái)活動(dòng)的組件回調(diào)偶妖,避免組件銷毀后發(fā)生意想不到的崩潰情況。
那LiveData是如何做到以上這些功能的呢纯陨?
LiveData如何是如何能觀察到組件生命周期的
從使用開(kāi)始入手源碼:
var myLiveData = MutableLiveData<Any>()
myLiveData.observe(this, Observer {
})
這里通過(guò)調(diào)用LiveData的observe()方法來(lái)注冊(cè)觀察者坛芽,LiveData的observe()方法如下:
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
//該方法調(diào)用者必須在主線程
assertMainThread("observe");
//如果處在DESTROYED 狀態(tài),則沒(méi)必要添加觀察者
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//將包裝結(jié)果添加到Map里
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);
}
方法的第一個(gè)參數(shù)owner翼抠,就是注冊(cè)時(shí)的組件咙轩,即為activity或fragment,需要為實(shí)現(xiàn)LifecycleOwner接口阴颖。獲取組件當(dāng)前的生命周期狀態(tài)活喊,如果狀態(tài)為DESTROYED,那么直接return量愧,這就保證了DESTROYED狀態(tài)的組件是不允許注冊(cè)的钾菊。
mObservers.putIfAbsent(observer, wrapper)方法將observer和LifecycleBoundObserver存儲(chǔ)到SafeIterableMap類型的mObservers中,putIfAbsent方法和put方法有區(qū)別偎肃,如果傳入key對(duì)應(yīng)的value已經(jīng)存在煞烫,就返回存在的value,不進(jìn)行替換累颂。如果不存在滞详,就添加key和value,返回null。
最后的owner.getLifecycle().addObserver(wrapper)料饥,就在LiveData內(nèi)部完成了Lifecycle的觀察者的添加蒲犬,這樣LiveData就有了觀察組件生命周期變化的能力。
LiveData是如何回調(diào)observe方法的
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
當(dāng)宿主(Activity/Fragment) 生命周期發(fā)生改變時(shí)會(huì)調(diào)用onStateChanged()方法稀火,并且判斷了當(dāng)組件處于DESTROYED狀態(tài)時(shí)暖哨,會(huì)調(diào)用removeObserver方法,來(lái)移除observer凰狞。所以當(dāng)組件銷毀時(shí)篇裁,注冊(cè)的生命周周觀察者不會(huì)再接收到通知,因?yàn)橐呀?jīng)解綁了赡若。
shouldBeActive()用來(lái)判斷當(dāng)前宿主是否是活躍狀態(tài)达布,此處定義的活躍狀態(tài)為:宿主的狀態(tài)要>="STARTED"狀態(tài),而該狀態(tài)區(qū)間為:Activity.onStart() 之后且Activity.onPause()之前逾冬。
當(dāng)宿主處于活躍狀態(tài)時(shí)黍聂,才會(huì)繼續(xù)通知UI 數(shù)據(jù)變更了,進(jìn)而刷新UI身腻,若是處于非活躍狀態(tài)产还,比如App 失去焦點(diǎn)(onPause()被調(diào)用),那么將不會(huì)刷新UI 嘀趟。
通知觀察者
-
Observer的回調(diào)事件通過(guò)setValue和postValue觸發(fā)脐区。
setValue方法:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
從代碼中方法注解可以看出,setValue方法必須運(yùn)行在主線程中她按,其內(nèi)部調(diào)用了dispatchingValue方法牛隅,其后將事件通知回調(diào)給observers。
再看dispatchingValue方法:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
//遍歷調(diào)用所有觀察者
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
在分發(fā)有效的前提下酌泰,遍歷mObservers媒佣,一次調(diào)用considerNotify()方法。
private void considerNotify(ObserverWrapper observer) {
//非活躍狀態(tài)陵刹,直接返回
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//如果LiveData數(shù)據(jù)版本<= 觀察者的數(shù)據(jù)版本默伍,則直接返回
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
如果當(dāng)前observer的mActive值不為true,就直接return衰琐。如果判斷條件都滿足也糊,則調(diào)用Observer接口的onChanged()方法,這個(gè)方法正是開(kāi)頭myLiveData.observe(this, Observer {}) Observer接口的方法碘耳,因此完成liveData變化對(duì)observer回調(diào)事件的輪回显设。
public interface Observer<T> {
/**
* Called when the data is changed.
* @param t The new data
*/
void onChanged(T t);
}
postValue()
protected void postValue(T value) {
boolean postTask;
//子線程、主線程都需要修改mPendingData辛辨,因此需要加鎖
synchronized (mDataLock) {
//mPendingData 是否還在排隊(duì)等待發(fā)送出去
//mPendingData == NOT_SET 表示當(dāng)前沒(méi)有排隊(duì)
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
//說(shuō)明上次的Runnable 還沒(méi)執(zhí)行
//直接返回捕捂,不需要切換到主線程執(zhí)行
return;
}
//切換到主線程執(zhí)行Runnable
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
// 切換到主線程執(zhí)行Runnable
setValue((T) newValue);
}
};
而postValue方法里瑟枫,通過(guò)任務(wù)(Runnable)的方式在主線程中更新數(shù)據(jù)。而getValue中指攒,如果livedata中mData設(shè)過(guò)值就返回mData慷妙,否則會(huì)返回null,這里在實(shí)際使用中可能會(huì)造成空指針異常允悦。
livedata為什么連續(xù)post會(huì)丟失數(shù)據(jù)?
我們實(shí)際場(chǎng)景更多的是在子線程發(fā)起的膝擂,所以會(huì)用postValue來(lái)通知數(shù)據(jù)變化。
postValue里首先好會(huì)將分發(fā)的值賦值給mPendingData全局變量隙弛,然后將值的分發(fā)操作放在一個(gè)Runnable里進(jìn)行架馋,從postValue到 ArchTaskExecutor執(zhí)行postToMainThread方法(其實(shí)里面就是mMainHandler.post(runnable))是有一個(gè)時(shí)間間隙的。
在這個(gè)時(shí)間間隙中全闷,由于連續(xù)兩次postValue,所以mPendingData帶著第二次的最新值叉寂,進(jìn)行分發(fā),所以UI刷新总珠,只能看到第二次的值屏鳍。
其實(shí)剛才分析過(guò)程中我們也看到了,由于第二次執(zhí)行postValue的時(shí)候局服,mPendingData已經(jīng)不是初始值钓瞭,所以導(dǎo)致postTask為false,在3處淫奔,執(zhí)行了return山涡。所以雖然執(zhí)行了兩次postValue,可是ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable)只會(huì)執(zhí)行一次搏讶。
總結(jié)一下LiveData運(yùn)行流程:
1.通過(guò)調(diào)用LiveData的observe()方法來(lái)注冊(cè)觀察者佳鳖,獲取組件當(dāng)前的生命周期狀態(tài)霍殴,如果狀態(tài)為DESTROYED媒惕,那么直接return。owner.getLifecycle().addObserver(wrapper)来庭,就在LiveData內(nèi)部完成了Lifecycle的觀察者的添加妒蔚,這樣LiveData就有了觀察組件生命周期變化的能力。
2.當(dāng)組件狀態(tài)發(fā)生變化時(shí)月弛,會(huì)調(diào)用onStateChanged方法肴盏,并且判斷了當(dāng)組件處于DESTROYED狀態(tài)時(shí),會(huì)調(diào)用removeObserver方法來(lái)移除observer帽衙。具體事件分發(fā)是通過(guò)ObserverWrapper菜皂,它是Observer的包裝類,如果是Active狀態(tài)厉萝,會(huì)調(diào)用dispatchingValue方法恍飘,并將自身傳進(jìn)去榨崩。
3.在分發(fā)有效的前提下,遍歷mObservers章母,如果當(dāng)前observer的mActive值不為true母蛛,就直接return。如果判斷條件都滿足乳怎,則調(diào)用Observer接口的onChanged()方法彩郊。
4.最后,通過(guò)setValue和postValue方法內(nèi)部調(diào)用dispatchingValue方法蚪缀,其后將事件通知回調(diào)給observers秫逝。
粘性事件
LiveData數(shù)據(jù)變更發(fā)生后,才注冊(cè)的觀察者询枚,此時(shí)觀察者還能收到變更通知筷登。
這和LiveData 的實(shí)現(xiàn)有關(guān),看看核心源碼實(shí)現(xiàn):
private void considerNotify(LiveData.ObserverWrapper observer) {
//mVersion 為L(zhǎng)iveData 當(dāng)前數(shù)據(jù)版本哩盲,當(dāng)setValue/postValue 發(fā)生時(shí)前方,mVersion++
//通過(guò)比對(duì)LiveData 當(dāng)前數(shù)據(jù)版本與觀察者的數(shù)據(jù)版本,若是發(fā)現(xiàn)LiveData 當(dāng)前數(shù)據(jù)版本 更大
//說(shuō)明是之前沒(méi)有通知過(guò)觀察者廉油,因此需要通知惠险,反之則不通知。
if (observer.mLastVersion >= mVersion) {
return;
}
//將觀察者數(shù)據(jù)版本保持與LiveData 版本一致抒线,表明該觀察者消費(fèi)了最新的數(shù)據(jù)班巩。
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
再回溯一下流程:
1、初始時(shí)LiveData.mVersion= -1嘶炭,ObserverWrapper.mLastVersion = -1抱慌,因此初次進(jìn)入Activity時(shí)沒(méi)有數(shù)據(jù)通知。
2眨猎、當(dāng)點(diǎn)擊按鈕后(LiveData.setValue())抑进,此時(shí)LiveData.mVersion = 0;因?yàn)長(zhǎng)iveData.mVersion>ObserverWrapper.mLastVersion睡陪,因此觀察者能夠收到通知寺渗。
3、當(dāng)退出Activity 再進(jìn)來(lái)后兰迫,因?yàn)镺bserverWrapper 是全新new 出來(lái)的信殊,ObserverWrapper.mLastVersion = -1,而LiveData.mVersion =0汁果,還是大于 ObserverWrapper.mLastVersion涡拘,因此依然能夠收到通知。
參考:
https://blog.csdn.net/jwg1988/article/details/122925810
https://juejin.cn/post/7081841015643963406