是什么
是一個可觀察的數(shù)據(jù)存儲類疼鸟,且具備宿主生命周期的感知能力。
優(yōu)勢
- 頁面不可見時不會派發(fā)消息
- 頁面可見時,會立刻派發(fā)最新的一條消息給所有觀察者--保證頁面最新狀態(tài)
- 不再需要手動處理生命周期匿级,避免NPE
- 支持黏性事件的分發(fā)
- 共享資源,可以使用單例模式拓展 LiveData科雳,實現(xiàn)全局的根蟹,不用反注冊脓杉,不會內(nèi)存泄漏的消息分發(fā)總線糟秘。
各類之間的關系
注冊觀察者流程,事件分發(fā)原理
// LiveData.class
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
// 判斷是否主線程
assertMainThread("observe");
// 如果宿主已經(jīng)destroy球散,則return
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
// 用LifecycleBoundObserver包裝observer尿赚,其中包含LifecycleOwner,且能響應生命周期事, 如果頁面destroy了,可以將observer自動從lifecycle移除
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 將observer和wrapper保存起來凌净,如果之前已經(jīng)存在則返回之前的wrapper悲龟,否則返回null
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// 如果之前已經(jīng)添加過該observer,且observer不是綁定當前owner冰寻,拋出異常
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
// 如果之前已經(jīng)添加過該observer须教,則不再添加,return
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
// 更新mActiveCount斩芭,判斷是否觸發(fā)LiveData的onActive()和onInactive()
@MainThread
void changeActiveCounter(int change) {
int previousActiveCount = mActiveCount;
mActiveCount += change;
if (mChangingActiveState) {
return;
}
mChangingActiveState = true;
try {
// 更新mActiveCount
while (previousActiveCount != mActiveCount) {
boolean needToCallActive = previousActiveCount == 0 && mActiveCount > 0;
boolean needToCallInactive = previousActiveCount > 0 && mActiveCount == 0;
previousActiveCount = mActiveCount;
// 觸發(fā)onActive()或onInactive()
// 可以充分利用 onActive() 方法被激活的時機轻腺,來實現(xiàn)一些數(shù)據(jù)懶加載的功能。
if (needToCallActive) {
onActive();
} else if (needToCallInactive) {
onInactive();
}
}
} finally {
mChangingActiveState = false;
}
}
// 給Observer分發(fā)數(shù)據(jù)
void dispatchingValue(@Nullable ObserverWrapper initiator) {
// 如果正在分發(fā)數(shù)據(jù)划乖,則將mDispatchInvalidated置為true贬养,后面分發(fā)結束后會再分發(fā)一次
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
// 如果initiator則只給initiator分發(fā),否則給所有observer分發(fā)數(shù)據(jù)
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());
// 如果正在分發(fā)數(shù)據(jù)琴庵,dispatchingValue(observer)又被調用了误算,則停止本次分發(fā),重新開始分發(fā)
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
// 真正分發(fā)數(shù)據(jù)的地方
private void considerNotify(ObserverWrapper observer) {
// 如果observer所在頁面不是活躍狀態(tài)迷殿,則不分發(fā)數(shù)據(jù)
if (!observer.mActive) {
return;
}
// 獲取observer所在頁面的最新狀態(tài)儿礼,有可能頁面狀態(tài)變了,但是還沒更新Observer的mActive
// 我們?nèi)匀幌扰袛鄌bserver.mActive庆寺,如果頁面已經(jīng)變?yōu)榛钴S狀態(tài)蜘犁,但是observer.mActive還沒更新,即還是不活躍狀態(tài)止邮,則更新observer.mActive这橙,但仍不分發(fā)數(shù)據(jù)
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// observer的數(shù)據(jù)版本大于LiveData的版本,即接收數(shù)據(jù)的次數(shù)大于發(fā)送數(shù)據(jù)的次數(shù)导披,說明observer已經(jīng)收到最新的數(shù)據(jù)屈扎,不再回調observer#onChanged()通知更新
// observer的mLastVersion=-1,如果之前已經(jīng)發(fā)送過數(shù)據(jù)了撩匕,即mLastVersion<mVersion鹰晨,則會出現(xiàn)黏性事件,后注冊的觀察者收到了前面發(fā)送的消息
if (observer.mLastVersion >= mVersion) {
return;
}
// 每分發(fā)一次消息止毕,則把觀察者和LiveData的version對齊模蜡,防止重復發(fā)送
observer.mLastVersion = mVersion;
// 通知更新
observer.mObserver.onChanged((T) mData);
}
#########################################################
// LifecycleBoundObserver.class
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
// 當前界面是否活躍,即當前界面狀態(tài)是否大于STARED
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
// 當生命周期變化時回調
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
// 獲取當前界面狀態(tài)
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
// 如果當前界面已經(jīng)銷毀扁凛,則移除observer
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
// 給父類OvserverWrapper設置活躍狀態(tài)忍疾,如果是活躍的話分發(fā)數(shù)據(jù)
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
// ObserverWrapper.class
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
// 設置活躍狀態(tài),如果是活躍的話分發(fā)數(shù)據(jù)
void activeStateChanged(boolean newActive) {
// 狀態(tài)一樣不做處理
if (newActive == mActive) {
return;
}
mActive = newActive;
// 更新mActiveCount谨朝,判斷是否出發(fā)LiveData的onActive()和onInactive()
changeActiveCounter(mActive ? 1 : -1);
// 如果是活躍的話卤妒,分發(fā)數(shù)據(jù)
if (mActive) {
dispatchingValue(this);
}
}
}
小結
- 首先調用LiveData#observe(owner, observer)進行注冊甥绿,這時會將observer包裝成LifecycleBoundObserver
- LifecycleBoundObserver繼承自ObserverWrapper乍狐,保存了Observer和LifecycleOwner脚囊,所以可以回調observer#onChanged(data),也可以從LifecycleOwner中獲得頁面活躍狀態(tài)谭确;同時它實現(xiàn)了LifecycleEventObserver士复,所以能夠監(jiān)聽lifecycle的生命周期事件图谷,在頁面銷毀時移除observer,在頁面變?yōu)榛钴S狀態(tài)時阱洪,接收最新的數(shù)據(jù)(如果之前沒有接收過的話)蜓萄。
- 如果是在頁面onResume是注冊的觀察者,onStateChanged(owner, event)會回調3次:onCreate澄峰、onStart嫉沽、onResume。但是observer#onChanged(data)只會回調一次俏竞,因為onStateChanged(owner, event)會判斷如果頁面狀態(tài)和之前一樣(mActive沒有改變)绸硕,則return。
- 另外即使mActive改變了魂毁,但是如果數(shù)據(jù)沒有改變玻佩,也不會回調observer#onChanged(data),因為LiveData會根據(jù)ObserverWrapper#mLastVersion和自身的mVersion判斷數(shù)據(jù)的接收次數(shù)和發(fā)送次數(shù)是否一致:mLastVersion<mVersion則發(fā)送席楚;否則不發(fā)送咬崔。
- LifecycleBoundObserver#onStateChanged(owner, event)回調時,會根據(jù)是否有活躍的觀察者(mActiveCount)來觸發(fā)LiveData#onActive()/onInactive()
- 之后就會判斷頁面是否活躍烦秩,如果活躍則分發(fā)數(shù)據(jù)垮斯,調用considerNotify方法,通過ObserverWrapper#mLastVersion和LiveData#mVersion來判斷是否觸發(fā)Observer#onChanged(data)
發(fā)送數(shù)據(jù)
// LiveData.class
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
// 加鎖只祠,防止主線程更新數(shù)據(jù)時兜蠕,mPendingData被改變
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
protected void postValue(T value) {
boolean postTask;
// 加鎖,防止主線程更新數(shù)據(jù)時抛寝,mPendingData被改變
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
// 如果postTask=false熊杨,說明正在等待runnable獲取mPendingData更新界面,不再發(fā)送runnable
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
// 增加發(fā)送次數(shù)
mVersion++;
mData = value;
// 通知所有的observer更新數(shù)據(jù)
dispatchingValue(null);
}
數(shù)據(jù)倒灌是什么
頁面在再次打開時盗舰,收到了舊數(shù)據(jù)晶府。
比如,有3個fragment:列表钻趋、詳情川陆、編輯,它們都共享viewmodel中的同一個liveData爷绘,在編輯頁編輯完后通過livedata保存數(shù)據(jù)书劝,退出返回詳情頁時,詳情頁恢復活躍狀態(tài)土至,會從liveData收到最新的數(shù)據(jù)更新界面购对。再次回退到列表頁,點擊另一個item打開詳情頁陶因,這時詳情頁調用liveData#addObserver()會從liveData收到之前到舊數(shù)據(jù)骡苞,這就是數(shù)據(jù)倒灌。
如果解決黏性事件
反射干涉Version
不推薦這種方式楷扬,網(wǎng)上的方案是在LiveData#observe()
方法中利用反射修改LifecycleBoundObserver中的mLastVersion的值=LiveData的mVersion解幽,但是這種方案只適合在頁面的onCreate(頁面還不是活躍狀態(tài))時注冊observer,因為這時頁面的state是INITIALIZED烘苹, 在LiveData#observe()->LifecycleRegistrty#addObserver()
中由于LifecycleRegistrty.mState=LifecycleBoundObserver.mState
躲株,導致不會回調ObserverWithState#dispatchEvent()->LifecycleBoundObserver#onStateChanged()
,從而不會觸發(fā)observer.onChanged()镣衡,也就達到了取消粘性事件的目的霜定。但是如果在onStart()或之后(頁面變?yōu)榛钴S狀態(tài))注冊observer,由于這時頁面的state是大于INITIALIZED的廊鸥, 所以在LiveData#observe()->LifecycleRegistrty#addObserver()
中會觸發(fā)ObserverWithState#dispatchEvent()->LifecycleBoundObserver#onStateChanged()
望浩,也就導致observer.onChanged()被觸發(fā),還是發(fā)生粘性事件惰说。自定義LiveData和Observer磨德,分別在內(nèi)部維護一個version。當不需要粘性事件時吆视,在用LiveData注冊Observer時典挑,將LiveData的version賦值給observer的version;當需要粘性事件時啦吧,在用LiveData注冊Observer時搔弄,設置Observer的version為-1。
參考:https://github.com/KunMinX/UnPeek-LiveData/blob/de958b679b/unpeeklivedata/src/main/java/com/kunminx/architecture/ui/callback/ProtectedUnPeekLiveData.java#L40-L176
public class ProtectedUnPeekLiveData<T> extends LiveData<T> {
private final static int START_VERSION = -1;
private final AtomicInteger mCurrentVersion = new AtomicInteger(START_VERSION);
protected boolean isAllowNullValue;
/**
* TODO tip:當 liveData 用作 event 用途時丰滑,可使用該方法來觀察 "生命周期敏感" 的非粘性消息
* <p>
* state 是可變且私用的顾犹,event 是只讀且公用的,
* state 的倒灌是應景的褒墨,event 倒灌是不符預期的炫刷,
* <p>
* 如果這樣說還不理解,詳見《LiveData 唯一可信源 讀寫分離設計》的解析:
* https://xiaozhuanlan.com/topic/2049857631
*
* @param owner activity 傳入 this郁妈,fragment 建議傳入 getViewLifecycleOwner
* @param observer observer
*/
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
super.observe(owner, createObserverWrapper(observer, mCurrentVersion.get()));
}
/**
* TODO tip:當 liveData 用作 event 用途時浑玛,可使用該方法來觀察 "生命周期不敏感" 的非粘性消息
*
* @param observer observer
*/
@Override
public void observeForever(@NonNull Observer<? super T> observer) {
super.observeForever(createObserverWrapper(observer, mCurrentVersion.get()));
}
/**
* TODO tip:當 liveData 用作 state 用途時,可使用該方法來觀察 "生命周期敏感" 的粘性消息
*
* @param owner activity 傳入 this噩咪,fragment 建議傳入 getViewLifecycleOwner
* @param observer observer
*/
public void observeSticky(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
super.observe(owner, createObserverWrapper(observer, START_VERSION));
}
/**
* TODO tip:當 liveData 用作 state 用途時顾彰,可使用該方法來觀察 "生命周期不敏感" 的粘性消息
*
* @param observer observer
*/
public void observeStickyForever(@NonNull Observer<? super T> observer) {
super.observeForever(createObserverWrapper(observer, START_VERSION));
}
/**
* TODO tip:只需重寫 setValue
* postValue 最終還是會經(jīng)過這里
*
* @param value value
*/
@Override
protected void setValue(T value) {
mCurrentVersion.getAndIncrement();
super.setValue(value);
}
/**
* TODO tip:
* 1.添加一個包裝類极阅,自己維護一個版本號判斷,用于無需 map 的幫助也能逐一判斷消費情況
* 2.重寫 equals 方法和 hashCode涨享,在用于手動 removeObserver 時筋搏,忽略版本號的變化引起的變化
*/
class ObserverWrapper implements Observer<T> {
private final Observer<? super T> mObserver;
private int mVersion = START_VERSION;
public ObserverWrapper(@NonNull Observer<? super T> observer, int version) {
this.mObserver = observer;
this.mVersion = version;
}
@Override
public void onChanged(T t) {
if (mCurrentVersion.get() > mVersion && (t != null || isAllowNullValue)) {
mObserver.onChanged(t);
}
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ObserverWrapper that = (ObserverWrapper) o;
return Objects.equals(mObserver, that.mObserver);
}
@Override
public int hashCode() {
return Objects.hash(mObserver);
}
}
/**
* TODO tip:
* 通過 ObserveForever 的 Observe,需要記得 remove厕隧,不然存在 LiveData 內(nèi)存泄漏的隱患奔脐,
* 保險的做法是,在頁面的 onDestroy 環(huán)節(jié)安排 removeObserver 代碼吁讨,
* 具體可參見 app module 中 ObserveForeverFragment 的案例
*
* @param observer observeForever 注冊的 observer髓迎,或 observe 注冊的 observerWrapper
*/
@Override
public void removeObserver(@NonNull Observer<? super T> observer) {
if (observer.getClass().isAssignableFrom(ObserverWrapper.class)) {
super.removeObserver(observer);
} else {
super.removeObserver(createObserverWrapper(observer, START_VERSION));
}
}
private ObserverWrapper createObserverWrapper(@NonNull Observer<? super T> observer, int version) {
return new ObserverWrapper(observer, version);
}
/**
* TODO tip:
* 手動將消息從內(nèi)存中清空,
* 以免無用消息隨著 SharedViewModel 的長時間駐留而導致內(nèi)存溢出的發(fā)生建丧。
*/
public void clear() {
super.setValue(null);
}
}