入門
簡介
GitHub:EventBus
Android optimized event bus that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.
android最佳的事件總線,簡化了Activities、Fragments、Threads、Services等之間的通信,代碼更少,質量更好。
EventBus是greenrobot團隊Markus Junginger開源的發布-訂閱事件總線庫。主要用于:適合當做組件間的通訊工具使用,主要用來傳遞消息。請求網絡,等網絡返回時通過Handler或Broadcast通知UI,兩個Fragment之間需要通過Listener通信,這些需求都可以通過EventBus實現。。。。
優點有
簡潔性。簡化了應用程序內各組件間、組件與后臺線程間的通信。
開銷小。代碼更優雅。
低耦合。將發送者和接受者解耦。
缺點是
事件一般都要寫個對應的 Event 類出來,導致會都很多這些類;
可讀性降低。兩個模塊間交互,不如原來定位快。
EventBus3.0較之前版本:用注解的方式代替約定的方法名規范。
其他框架對比
RxBus:使用RxJava實現的庫。缺點有:如何實現sticky功能;如何處理RxJava的訂閱操作中的異常導致的訂閱的中斷(因為RxJava中出現異常會直接跳轉OnError,事件流就被中斷了);使用運行時(Run-time)注解的話,反射的性能問題。
Guava:Google的Guava是一個龐大的庫,EventBus只是它附帶的一個小功能,因此實際項目中使用并不多。
Otto:square的otto修改自 Guava。但已停止維護,臨死前推薦大家使用RxBus。
基礎用法
使用
基本使用大致分為5個步驟:
1,創建事件類;(用一個POJO封裝傳遞數據。如果是簡單的基本數據類型,不封裝也行。)
2,在訂閱事件處注冊事件;(在發送端)
EventBus.getDefault().register(this);
3,發送事件;(此為發布者,在發送端)
EventBus.getDefault().post(new EventPOJO("Hello EventBus!"));
4,接收,處理事件;(此為訂閱者,在接收端)
//接收方法可以隨便起名,但需要添加Subscribe注解。
@Subscribe(threadMode= ThreadMode.MAIN)
public voidonEvent(EventPOJO messageEvent) {
tv_message.setText(messageEvent.getMessage());
}
5,注銷總線。
EventBus.getDefault().unregister(this);
@Subscribe
ThreadMode提供了四種類型。MainThread 主線程,BackgroundThread 后臺線程,Async 后臺線程,PostThread 發送線程(默認)。
- POSTING(默認):如果使用事件處理函數指定了線程模型為POSTING,那么該事件在哪個線程發布出來的,事件處理函數就會在這個線程中運行,也就是說發布事件和接收事件在同一個線程。在線程模型為POSTING的事件處理函數中盡量避免執行耗時操作,因為它會阻塞事件的傳遞,甚至有可能會引起ANR。
- MAIN:事件的處理會在UI線程中執行。事件處理時間不能太長,長了會ANR的。
- BACKGROUND:如果事件是在UI線程中發布出來的,那么該事件處理函數就會在新的線程中運行,如果事件本來就是子線程中發布出來的,那么該事件處理函數直接在發布事件的線程中執行。在此事件處理函數中禁止進行UI更新操作。
- ASYNC:無論事件在哪個線程發布,該事件處理函數都會在新建的子線程中執行,同樣,此事件處理函數中禁止進行UI更新操作。
sticky機制
sticky機制俗稱粘性事件。即發送事件之后再訂閱該事件也能收到該事件。sticky默認值為false,在Subscribe方法中可以更改。
@Subscribe(threadMode = ThreadMode.POSTING,priority = 1, sticky = true)
priority 值表示優先級。值越小優先級越低,默認為0。
1,訂閱粘性事件;
bt_subscription.setOnClickListener(newView.OnClickListener() {
@OverridepublicvoidonClick(View v) {//注冊事件
EventBus.getDefault().register(MainActivity.this);
}
});
2,處理粘性事件;
@Subscribe(threadMode = ThreadMode.POSTING,priority=0, sticky =true)
publicvoidononMoonStickyEvent(MessageEvent messageEvent){
tv_message.setText(messageEvent.getMessage());
}
3,發送粘性事件。
bt_subscription.setOnClickListener(newView.OnClickListener() {
@OverridepublicvoidonClick(View v) {
EventBus.getDefault().postSticky(newMessageEvent("粘性事件"));
finish();
}
});
進階用法
添加processor
由于使用了注解,性能會降低。使用processor在編譯的時候為注冊類構建了一個索引,而不是在運行時,這樣的結果是其讓EventBus 3.0的性能提升了一倍,相比2.4來說,其會是它的3到6倍。
使用processor有兩種方案。<一>添加依賴:provided'de.greenrobot:eventbus-annotation-processor:3.0.0-beta1';
<二>添加依賴:apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'。在Application中添加EventBus.builder().addIndex(newMyEventBusIndex()).installDefaultEventBus();。
源碼解析
EventBus是用了反射,并且維護了一個全局map,記錄event到method的映射。
通過注解把類中的所有訂閱者和訂閱信息提取出來,這里有很多過濾條件保證提取的正確性。
EventBus中有兩個映射表,subscriptionsByEventType中存放所有event和對應的訂閱者,typesBySubscriber中存放每個訂閱者對應的事件。提取出來的訂閱者和信息就被存進了這兩個表里。
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>>
subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
所有的的poster被放在3個隊列中,mainThreadPoster、backgroundPoster、asyncPoster。這3個隊列是用鏈表實現的,讓poster在各自的線程排隊,等候處理。如果是POSTING類型的事件,就直接執行了,不用排隊。
錯誤匯總
post了消息之后,你的訂閱者有多個,每一個都接收嗎?能否做到指定接收者。
使用經驗
EventBus最好都定義在一個包下,分散開后期不好維護。
參考文章
Android事件總線(一)EventBus3.0用法全解析 劉望舒
EventBus使用詳解(一)——初步使用EventBus 講的2.X,算的上比較早的blog了。貼上紀念下。