首先我們來(lái)看消息總線的進(jìn)化:
消息傳遞既可以用于Android四大組件之間的通信,也可用于異步線程和主線程之間的通信蛉顽,所以這是Android開(kāi)發(fā)中極為重要的一環(huán)。
從最早的Intent,Handler先较,BroadcastReceiver携冤,接口回調(diào),到最近幾年開(kāi)發(fā)者中流行的通信總線類的框架EventBus,RxBus闲勺。我們發(fā)現(xiàn)Android消息傳遞框架機(jī)制曾棕,總在不斷進(jìn)化中……
我們從EventBus說(shuō)起:
EventBus是一個(gè)Android事件發(fā)布/訂閱框架,通過(guò)解耦發(fā)布者和訂閱者簡(jiǎn)化Android事件傳遞菜循。
RxBus出現(xiàn):
趁著響應(yīng)式編程的風(fēng)翘地,RxBus其實(shí)本身不需要過(guò)多的分析,其強(qiáng)大完全依賴于RxJava技術(shù),RxJava天生就是發(fā)布/訂閱模式衙耕,而且很容易線程切換昧穿,所以RxBus憑借區(qū)區(qū)30行代碼,就打敗了EventBus統(tǒng)治多年的老大地位橙喘。
原理:
在RxJava中有個(gè)Subject類时鸵,它繼承Observable類,同時(shí)實(shí)現(xiàn)了Observer接口厅瞎,因此Subject可以同時(shí)擔(dān)當(dāng)訂閱者和被訂閱者的角色饰潜,我們使用Subject的子類PublishSubject來(lái)創(chuàng)建一個(gè)Subject對(duì)象(PublishSubject只有被訂閱后才會(huì)把接收到的事件立刻發(fā)送給訂閱者),在需要接收事件的地方和簸,訂閱該Subject對(duì)象囊拜,之后如果Subject對(duì)象接收到事件,則會(huì)發(fā)射給該訂閱者比搭,此時(shí)Subject對(duì)象充當(dāng)被訂閱者的角色冠跷。
完成了訂閱,在需要發(fā)送事件的地方將事件發(fā)送給之前被訂閱的Subject對(duì)象身诺,則此時(shí)Subject對(duì)象作為訂閱者接收事件蜜托,然后會(huì)立刻將事件轉(zhuǎn)發(fā)給訂閱該Subject對(duì)象的訂閱者,以便訂閱者處理相應(yīng)事件霉赡,到這里就完成了事件的發(fā)送與處理橄务。
最后就是取消訂閱的操作了,RxJava中穴亏,訂閱操作會(huì)返回一個(gè)Subscription對(duì)象蜂挪,以便在合適的時(shí)機(jī)取消訂閱,防止內(nèi)存泄漏嗓化,如果一個(gè)類產(chǎn)生多個(gè)Subscription對(duì)象棠涮,我們可以用一個(gè)CompositeSubscription存儲(chǔ)起來(lái),以進(jìn)行批量的取消訂閱刺覆。
RxBus兩種實(shí)現(xiàn):
AndroidKnife/RxBus(https://github.com/AndroidKnife/RxBus)
Blankj/RxBus(https://github.com/Blankj/RxBus)
基于Rxjava1的RxBus實(shí)現(xiàn):
public?finalclassRxBus{
privatefinalSubject?bus;
privateRxBus(){
bus?=newSerializedSubject<>(PublishSubject.create());
}
privatestaticclassSingletonHolder{
privatestaticfinalRxBus?defaultRxBus?=newRxBus();
}
publicstaticRxBusgetInstance(){
returnSingletonHolder.defaultRxBus;
}
/*
?????*?發(fā)送
?????*/
publicvoidpost(Object?o){
bus.onNext(o);
}
/*
?????*?是否有Observable訂閱
?????*/
publicbooleanhasObservable(){
returnbus.hasObservers();
}
/*
?????*?轉(zhuǎn)換為特定類型的Obserbale
?????*/
publicObservable<T>?toObservable(Class<T>?type){
returnbus.ofType(type);
}
}
基于RxJava2的RxBus實(shí)現(xiàn):
public?finalclassRxBus2{
????private?final?Subject<Object>?bus;
????private?RxBus2()?{
????????//?toSerialized?method?made?bus?thread?safe
????????bus?=?PublishSubject.create().toSerialized();
????}
publicstaticRxBus2getInstance(){
????????return?Holder.BUS;
????}
privatestaticclassHolder{
????????private?static?final?RxBus2?BUS?=?new?RxBus2();
????}
publicvoidpost(Objectobj){
????????bus.onNext(obj);
????}
publicObservabletoObservable(Class?tClass){
????????return?bus.ofType(tClass);
????}
publicObservabletoObservable(){
????????return?bus;
????}
publicbooleanhasObservers(){
????????return?bus.hasObservers();
????}
}
重頭戲:LiveDataBus來(lái)啦严肪!
LiveData是一個(gè)可以被觀察的數(shù)據(jù)持有類,他可以感知并遵循Activity谦屑,F(xiàn)ragmet或者Service等組件的生命周期驳糯。于此,可以做到僅在組件處于生命 周期激活狀態(tài)時(shí)才更新UI數(shù)據(jù)氢橙。
LiveData需要一個(gè)觀察者對(duì)象酝枢,一般是Observer類的具體實(shí)現(xiàn),當(dāng)觀察者處于Stated或者Resumed狀態(tài)時(shí)悍手,LiveData會(huì)通知觀察者數(shù)據(jù)變化帘睦。在觀察者處于其他狀態(tài)的=時(shí)喉磁,即使LiveData數(shù)據(jù)變化了,也不會(huì)通知官脓。
優(yōu)點(diǎn):
LiveData的優(yōu)點(diǎn)
UI和實(shí)時(shí)數(shù)據(jù)保持一致,因?yàn)長(zhǎng)iveData采用的是觀察者模式涝焙,這樣一來(lái)就可以在數(shù)據(jù)發(fā)生改變時(shí)獲得通知卑笨,更新UI。
避免內(nèi)存泄漏仑撞,觀察者被綁定到組件的生命周期上赤兴,當(dāng)被綁定的組件銷毀(destroy)時(shí),觀察者會(huì)立刻自動(dòng)清理自身的數(shù)據(jù)隧哮。
不會(huì)再產(chǎn)生由于Activity處于stop狀態(tài)而引起的崩潰桶良,例如:當(dāng)Activity處于后臺(tái)狀態(tài)時(shí),是不會(huì)收到LiveData的任何事件的沮翔。
不需要再解決生命周期帶來(lái)的問(wèn)題陨帆,LiveData可以感知被綁定的組件的生命周期,只有在活躍狀態(tài)才會(huì)通知數(shù)據(jù)變化采蚀。
實(shí)時(shí)數(shù)據(jù)刷新疲牵,當(dāng)組件處于活躍狀態(tài)或者從不活躍狀態(tài)到活躍狀態(tài)時(shí)總是能收到最新的數(shù)據(jù)。
解決Configuration Change問(wèn)題榆鼠,在屏幕發(fā)生旋轉(zhuǎn)或者被回收再次啟動(dòng)纲爸,立刻就能收到最新的數(shù)據(jù)。
什么是Android Architecture Components 妆够?
Android Architecture ComponentsAndroid Architecture Components的核心是Lifecycle识啦、LiveData、ViewModel 以及 Room神妹,通過(guò)它可以非常優(yōu)雅的讓數(shù)據(jù)與界面進(jìn)行交互颓哮,并做一些持久化的操作,高度解耦鸵荠,自動(dòng)管理生命周期题翻,而且不用擔(dān)心內(nèi)存泄漏的問(wèn)題。
Android Architecture Components 特點(diǎn) 腰鬼?
數(shù)據(jù)驅(qū)動(dòng)型編程變化的永遠(yuǎn)是數(shù)據(jù)嵌赠,界面無(wú)需更改。感知生命周期熄赡,防止內(nèi)存泄漏高度解耦數(shù)據(jù)姜挺,界面高度分離。數(shù)據(jù)持久化數(shù)據(jù)彼硫、ViewModel不與 UI的生命周期掛鉤炊豪,不會(huì)因?yàn)榻缑娴闹亟ǘN毀凌箕。
Room
一個(gè)強(qiáng)大的SQLite對(duì)象映射庫(kù)。
ViewModel
一類對(duì)象词渤,它用于為UI組件提供數(shù)據(jù)牵舱,在設(shè)備配置發(fā)生變更時(shí)依舊可以存活。
LiveData一個(gè)可感知生命周期缺虐、可被觀察的數(shù)據(jù)容器芜壁,它可以存儲(chǔ)數(shù)據(jù),還會(huì)在數(shù)據(jù)發(fā)生改變時(shí)進(jìn)行提醒高氮。
Lifecycle
包含LifeCycleOwer和LifecycleObserver慧妄,分別是生命周期所有者和生命周期感知者。
重點(diǎn):為什么使用LiveData構(gòu)建數(shù)據(jù)通信總線LiveDataBus?
1,具有可觀察性和生命周期感知能力
2剪芍,不用顯示調(diào)用反注冊(cè)
組成:
消息
消息可以是任何的Object塞淹,可以定義不同類型的消息,如Boolean罪裹、String饱普。也可以定義自定義類型的消息。
消息通道
LiveData扮演了消息通道的角色状共,不同的消息通道用不同的名字區(qū)分费彼,名字是String類型的,可以通過(guò)名字獲取到一個(gè)LiveData消息通道口芍。
消息總線
消息總線通過(guò)單例實(shí)現(xiàn)箍铲,不同的消息通道存放在一個(gè)HashMap中。
訂閱
訂閱者通過(guò)getChannel獲取消息通道鬓椭,然后調(diào)用observe訂閱這個(gè)通道的消息颠猴。
發(fā)布
發(fā)布者通過(guò)getChannel獲取消息通道,然后調(diào)用setValue或者postValue發(fā)布消息小染。
第一個(gè)實(shí)現(xiàn):
public?finalclassLiveDataBus{
privatefinalMap>?bus;
privateLiveDataBus(){
bus?=newHashMap<>();
}
privatestaticclassSingletonHolder{
privatestaticfinalLiveDataBus?DATA_BUS?=newLiveDataBus();
}
publicstaticLiveDataBusget(){
returnSingletonHolder.DATA_BUS;
}
publicMutableLiveData<T>?getChannel(String?target,?Class<T>?type){
if(!bus.containsKey(target))?{
bus.put(target,newMutableLiveData<>());
}
return(MutableLiveData)?bus.get(target);
}
publicMutableLiveDatagetChannel(String?target){
returngetChannel(target,?Object.class);
}
}
接下來(lái)是注冊(cè)訂閱:
LiveDataBus.get().getChannel("key_test",?Boolean.class)
.observe(this,new?Observer()?{
@Override
publicvoidonChanged(@NullableBoolean?aBoolean)?{
}
});
接下來(lái)是發(fā)送消息:
LiveDataBus.get().getChannel("key_test").setValue(true);
但是這種實(shí)現(xiàn)會(huì)出現(xiàn)一個(gè)問(wèn)題翘瓮,那就是訂閱者會(huì)收到訂閱之前發(fā)布的消息。
所以最終的LiveDataBus封裝如下:
public?finalclassLiveDataBus{
privatefinalMap>?bus;
privateLiveDataBus(){
bus?=newHashMap<>();
}
privatestaticclassSingletonHolder{
privatestaticfinalLiveDataBus?DEFAULT_BUS?=newLiveDataBus();
}
publicstaticLiveDataBusget(){
returnSingletonHolder.DEFAULT_BUS;
}
publicMutableLiveData<T>?with(String?key,?Class<T>?type){
if(!bus.containsKey(key))?{
bus.put(key,newBusMutableLiveData<>());
}
return(MutableLiveData)?bus.get(key);
}
publicMutableLiveDatawith(String?key){
returnwith(key,?Object.class);
}
privatestaticclassObserverWrapperimplementsObserver{
privateObserver?observer;
publicObserverWrapper(Observer<T>?observer){
this.observer?=?observer;
}
@Override
publicvoidonChanged(@Nullable?T?t){
if(observer?!=null)?{
if(isCallOnObserve())?{
return;
}
observer.onChanged(t);
}
}
privatebooleanisCallOnObserve(){
StackTraceElement[]?stackTrace?=?Thread.currentThread().getStackTrace();
if(stackTrace?!=null&&?stackTrace.length?>0)?{
for(StackTraceElement?element?:?stackTrace)?{
if("android.arch.lifecycle.LiveData".equals(element.getClassName())?&&
"observeForever".equals(element.getMethodName()))?{
returntrue;
}
}
}
returnfalse;
}
}
privatestaticclassBusMutableLiveDataextendsMutableLiveData{
privateMap?observerMap?=newHashMap<>();
@Override
publicvoidobserve(@NonNull?LifecycleOwner?owner,?@NonNull?Observer<T>?observer){
super.observe(owner,?observer);
try{
hook(observer);
}catch(Exception?e)?{
e.printStackTrace();
}
}
@Override
publicvoidobserveForever(@NonNull?Observer<T>?observer){
if(!observerMap.containsKey(observer))?{
observerMap.put(observer,newObserverWrapper(observer));
}
super.observeForever(observerMap.get(observer));
}
@Override
publicvoidremoveObserver(@NonNull?Observer<T>?observer){
Observer?realObserver?=null;
if(observerMap.containsKey(observer))?{
realObserver?=?observerMap.remove(observer);
}else{
realObserver?=?observer;
}
super.removeObserver(realObserver);
}
privatevoidhook(@NonNull?Observer<T>?observer)throwsException{
//get?wrapper's?version
????????????Class<LiveData>?classLiveData?=?LiveData.class;
????????????Field?fieldObservers?=?classLiveData.getDeclaredField("mObservers");
????????????fieldObservers.setAccessible(true);
????????????Object?objectObservers?=?fieldObservers.get(this);
????????????Class<?>?classObservers?=?objectObservers.getClass();
????????????Method?methodGet?=?classObservers.getDeclaredMethod("get",?Object.class);
????????????methodGet.setAccessible(true);
????????????Object?objectWrapperEntry?=?methodGet.invoke(objectObservers,?observer);
????????????Object?objectWrapper?=?null;
????????????if?(objectWrapperEntry?instanceof?Map.Entry)?{
????????????????objectWrapper?=?((Map.Entry)?objectWrapperEntry).getValue();
????????????}
????????????if?(objectWrapper?==?null)?{
????????????????throw?new?NullPointerException("Wrapper?can?not?be?bull!");
????????????}
????????????Class<?>?classObserverWrapper?=?objectWrapper.getClass().getSuperclass();
????????????Field?fieldLastVersion?=?classObserverWrapper.getDeclaredField("mLastVersion");
????????????fieldLastVersion.setAccessible(true);
????????????//get?livedata's?version
????????????Field?fieldVersion?=?classLiveData.getDeclaredField("mVersion");
????????????fieldVersion.setAccessible(true);
????????????Object?objectVersion?=?fieldVersion.get(this);
????????????//set?wrapper's?version
????????????fieldLastVersion.set(objectWrapper,?objectVersion);
????????}
????}
}
注冊(cè)訂閱:
LiveDataBus.get()
????????.with("key_test",?String.class)
.observe(this,new?Observer()?{
@Override
publicvoidonChanged(@NullableString?s)?{
}
});
發(fā)送消息:
LiveDataBus.get().with("key_test").setValue(s);
源碼庫(kù)地址如下:
https://github.com/JeremyLiao/LiveDataBus
訂閱者可以訂閱某個(gè)消息通道的消息裤翩,發(fā)布者可以把消息發(fā)布到消息通道上资盅。利用LiveDataBus,不僅可以實(shí)現(xiàn)消息總線功能踊赠,而且對(duì)于訂閱者呵扛,他們不需要關(guān)心何時(shí)取消訂閱,極大減少了因?yàn)橥浫∠嗛喸斐傻膬?nèi)存泄漏風(fēng)險(xiǎn)筐带。