事件總線,繼承自觀察者模式,也是基于發(fā)布訂閱的機制來實現(xiàn)事件的發(fā)送與接收的。
Eventbus是一個專門為Android平臺優(yōu)化定制的事件總線函數(shù)庫,在3.0版本之后,使用注解進行事件的訂閱。在3.0的版本中,使用的注解類型為Runtime,因此在運行時會通過反射進行解析,會帶來一定的性能損耗。
只需要在Module里面的build.gradle添加依賴即可以引用
compile 'org.greenrobot:eventbus:3.0.0'
Eventbus的使用
注冊以及接收消息
注冊
注冊和注銷的代碼分別為:
EventBus.getDefault().register(this);
EventBus.getDefault().unregister(this);
一般而言,注冊和取消注冊時機應(yīng)該和組件的生命周期相關(guān)聯(lián),對于Activity,應(yīng)該在onStart/onStop對應(yīng)注冊取消,在界面銷毀后沒有取消注冊,將會造成內(nèi)存泄漏。在本人的測試中,使用界面A啟動界面B,當(dāng)B返回時不進行注銷,使用LeakCanary進行檢測,會檢測到泄漏
@Override
protected void onStop() {
super.onStop();
//注釋掉下面這句,將會產(chǎn)生泄漏
EventBus.getDefault().unregister(this);
}
接收消息
對于EventBus消息的接收,在3.0版本,方法名是任意的,但是必須進行@Subcribe的聲明,@Subcribe的定義如下
@Documented
//為運行時注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
//聲明該方法運行在哪個線程,默認是發(fā)送線程,可見官網(wǎng)解釋
ThreadMode threadMode() default ThreadMode.POSTING;
/**
* 如果是真,則接收最新的{@link EventBus#postSticky(Object)})消息
*這個可以用來解決界面跳轉(zhuǎn)所帶來的消息傳遞
*/
boolean sticky() default false;
/**
* 優(yōu)先級,默認是0,數(shù)值越大等級越高,等級高的可以取消事件的傳遞
*/
int priority() default 0;
}
由上述解釋,可以有以下的消息接收方式:
@Subscribe
public void eventGet(MessageEvent event){
bnChange.setText(event.getName() + "\n" + event.getMessage());
}
/**
* 粘性事件,注冊的時候就會檢測以前有沒有該類型的消息,有的話就調(diào)用該方法
* @param event 自定義的事件,只會接受該類型的事件,默認還可以接收其子類的事件
*/
@Subscribe(sticky = true)
public void onActivityGet(SecondActivityEvent event){
textView.setText(event.getMsg());
}
對于消息的接收,主要是通過方法參數(shù)決定的, 所以如果有很多不同的事件對應(yīng)不同的處理,那么需要自定義消息格式,否則會由于消息參數(shù)一致,否則參數(shù)相同的聲明方法都將會被反射調(diào)用。
事件的發(fā)布
對于事件的發(fā)布,比較簡單,主要有兩種方式,見代碼解釋
/**
*發(fā)送普通消息,只用當(dāng)前注冊了該事件的訂閱者才能夠接收到消息
*/
EventBus.getDefault().post(new MessageEvent(integer.incrementAndGet() + "", "activity 傳遞事件"));
/**
*發(fā)送粘性事件,當(dāng)前注冊了該事件的訂閱者能夠接收到消息
* 此外,該事件會被EventBus保存,當(dāng)有監(jiān)聽器注冊并且方法的聲明包括{@Subscribe(sticky = true)}
* 方法會被調(diào)用
* 注意:EventBus只會保存最新的一條消息,會把原來的消息覆蓋掉
*/
EventBus.getDefault().postSticky(new SecondActivityEvent(integer.get() + ""));
對于第二個方法,在保存消息之后,還會再調(diào)用第一個方法。
使用總結(jié)
EventBus的使用比較簡單,可以按照官網(wǎng)圖的方式來進行理解。EventBus相當(dāng)于郵箱,發(fā)布者直接把信息放到信箱,信箱會自動把信息發(fā)給訂閱了的人。
構(gòu)造函數(shù)原理
一般我們不需要顯式創(chuàng)建EventBus的實例,直接通過調(diào)用EventBus#getDefault獲取全局唯一單例即可,對于構(gòu)造函數(shù),可以通過下面的流程圖解釋:
具體的構(gòu)造代碼就不貼了, 可以自己下載源碼查看.
EventBus#regiser流程及原理
整體注冊流程如下所示:
相對來說整體流程還是比較清晰的, 有一些小細節(jié)沒有在流程圖繪制出來,注冊的方法如下所示:
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
對于獲取主體相對應(yīng)的方法,在EventBus的官網(wǎng)上,有兩種方法,一種是直接通過運行時反射獲取,還有一種是通過EventBusAnnotationProcessor進行編譯時期的@Subscribe注解解析。相對來說第二種方法會快很多。
還有一個就是對于主體里面聲明了@Subscribe(Sticky = true)的方法,在綁定的時候就會進行反射調(diào)用,當(dāng)然前提是本身EventBus有對應(yīng)的消息。
EventBus#post流程及原理
對于整個發(fā)送事件, 流程圖如下所示:
整個發(fā)送流程的源代碼這里就不進行貼出了,主要注意的是,對于發(fā)送粘性事件的發(fā)送方式,其實也是會調(diào)用到普通的消息發(fā)送方式的。
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
總結(jié)
這篇文章主要就是通過流程圖來解釋整個EventBus的工作過程,源碼解釋貼的比較少,可以自己去看源碼結(jié)合流程圖來進行分析。
github:https://github.com/ZCYL/TextCompile.git