前言
上一節(jié)內(nèi)容我們已經(jīng)充分介紹了LiveData組件,我們可以發(fā)現(xiàn)在使用LiveData分發(fā)數(shù)據(jù)的時(shí)候,是不會(huì)耦合任何Context獨(dú)享的,所以這個(gè)機(jī)制就從框架層避免了NPE,OOM等問題。但與此同時(shí)我們也發(fā)現(xiàn)了一些問題,比如LiveData無法取消黏性事件。如果之前發(fā)送的時(shí)間,而后注冊(cè)的觀察者也能接受到這條消息,那么是有可能會(huì)給我們帶來麻煩的。
本節(jié)我們就要以一種優(yōu)雅的方式去解決這個(gè)黏性事件的問題,與此同時(shí)還要基于LiveData打造一款消息分發(fā)總線,支持跨頁(yè)面的數(shù)據(jù)發(fā)送與監(jiān)聽,從而徹底拋棄EventBus。
需求分析
- 基于LiveData組件
- 保證內(nèi)存不會(huì)泄露
- 不用反注冊(cè)消息總線
- 支持黏性事件
上面幾點(diǎn)就是我們要最終實(shí)現(xiàn)的效果。用法上和EventBus非常相像,但我們的優(yōu)勢(shì)不用手動(dòng)反注冊(cè),不用擔(dān)心內(nèi)存泄露了。
HiDataBus.with("eventName").observer(lifecycleOwner,sticky,new Observer<String>{
void onChanged(String data){
}
})
疑難解惑
消息分發(fā)核心方法:
void considerNotify(ObserverWrapper observer) {
//觀察者沒有處于活躍狀態(tài),則不分發(fā)。
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//觀察者接收的消息的次數(shù)>=livedata發(fā)送消息的次數(shù),不分發(fā)。
//如果之前已經(jīng)發(fā)送過數(shù)據(jù)了,新注冊(cè)的observer也能接收到最后一條數(shù)據(jù)。
if (observer.mLastVersion >= mVersion) {
return;
}
//根本原因在于ObserverWrapper的version字段在創(chuàng)建時(shí)=-1,沒有主動(dòng)和LiveData的mVersion字段對(duì)齊
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
控制黏性事件的突破口在于觀察者的version字段,我們要在注冊(cè)一個(gè)新的Observer時(shí)把它的mLastVersion字段和LiveData.mVersion字段主動(dòng)保持一致就可以了。
但是上面這個(gè)version字段我們都是拿不到也無法修改的,網(wǎng)絡(luò)上有種方案使用反射強(qiáng)行讓Observer的mLastVersion和LiveData.mVersion對(duì)齊,但是不夠優(yōu)雅。
所以我們的做法是使用代理設(shè)計(jì)模式,從而修改掉新注冊(cè)O(shè)bserver的行為,下面來看代碼:
class StickyObserver<T> implements Observer<T> {
private StickyLiveData<T> mLiveData;
private Observer<T> mObserver;
private boolean mSticky;
//標(biāo)記該observer已經(jīng)接收幾次數(shù)據(jù)了,用以過濾老數(shù)據(jù)重復(fù)接收
private int mLastVersion = 0;
public StickyObserver(StickyLiveData liveData, Observer<T> observer, boolean sticky) {
//比如先使用StickyLiveData發(fā)送了一條數(shù)據(jù)。StickyLiveData#version=1
//那當(dāng)我們創(chuàng)建WrapperObserver注冊(cè)進(jìn)去的時(shí)候
//需要把它的version和 StickyLiveData的version保持一致
//用以過濾老數(shù)據(jù),否則 豈不是會(huì)收到老的數(shù)據(jù)?
mLastVersion = mLiveData.mVersion;
}
@Override
public void onChanged(T t) {
if (mLastVersion >= mLiveData.mVersion) {
//但如果當(dāng)前observer它是關(guān)心 黏性事件的,則給他。
if (mSticky && mLiveData.mStickyData != null) {
mObserver.onChanged(mLiveData.mStickyData);
}
return;
}
mLastVersion = mLiveData.mVersion;
mObserver.onChanged(t);
}
}
支持黏性事件訂閱、分發(fā)的StickyLiveData,自己管控消息分發(fā)的時(shí)機(jī),相比于網(wǎng)絡(luò)盛傳的使用反射修改LiveData.mVersion字段的方式優(yōu)雅的太多了
public static class StickyLiveData<T> extends LiveData<T> {
private String mEventName;
private T mStickyData;
private int mVersion = 0;
public StickyLiveData(String eventName) {
mEventName = eventName;
}
@Override
public void setValue(T value) {
//每次發(fā)送消息,版本號(hào)就需要+1,因?yàn)槲覀冃枰ㄟ^這個(gè)version管控,要不要分發(fā)黏性事件。
mVersion++;
super.setValue(value);
}
@Override
public void postValue(T value) {
super.postValue(value);
}
public void setStickyData(T stickyData) {
//同步的方式發(fā)送黏性消息
this.mStickyData = stickyData;
setValue(stickyData);
}
public void postStickyData(T stickyData) {
//異步的形式發(fā)送消息
this.mStickyData = stickyData;
postValue(stickyData);
}
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
observerSticky(owner, observer, false);
}
public void observerSticky(LifecycleOwner owner, Observer<? super T> observer, boolean sticky) {
super.observe(owner, new WrapperObserver(this, observer, sticky));
owner.getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
//自動(dòng)反注冊(cè)
mHashMap.remove(mEventName);
}
}
});
}
}
總結(jié)
通過對(duì)LiveData的實(shí)戰(zhàn)應(yīng)用,我們?cè)僖淮戊柟塘薒iveData的消息分發(fā)機(jī)制實(shí)現(xiàn)原理。日常開發(fā)中,如果有跨頁(yè)面的消息分發(fā)需求的話已經(jīng)不需要我們?cè)僖肫渌魏慰蚣芰恕?/p>
