EventBus 是一個Android端優(yōu)化的 publish/subscribe 消息總線,簡化了應用程序各個組件間(Activity,Service,Fragment等),組件和后臺線程間的通信. 比如網(wǎng)絡請求 , 等網(wǎng)絡返回時通過Handler 或者 Broadcast 通知 UI , Fragment之間的通信 等功能都可以通過EventBus 實現(xiàn).
相關鏈接 :
EventBus 基本使用
- 在 build.gradle 中添加依賴,同步項目.
compile 'org.greenrobot:eventbus:3.0.0'
- 定義傳遞小的消息實體類, 這個類的內容可以自定義,比如我這里定義一個EventBusMsg類.
public class EventBusMsg {
// 類的結構是自定義的,我這類添加了一個 String類型的 name 字段 方便測試.
public String name;
public EventBusMsg(String name) {
this.name = name;
}
}
-
訂閱事件
訂閱事件需要進行三步設置,注冊,解注冊和定義事件接收函數(shù),比如我在MainActivity中接收事件進行如下操作.- 在MainActivity 的onCreate()方法中注冊EventBus .
@Override protected void onCreate(Bundle savedInstanceState) { ... // 1. 注冊 EventBus.getDefault().register(MainActivity.this); }
- 在MainActivity 的onDestroy() 方法中 解注冊 EventBus . 一定不要忘記解注冊否則可能會造成內存泄漏.
@Override protected void onDestroy() { super.onDestroy(); // 2. 解注冊 EventBus.getDefault().unregister(MainActivity.this); }
- 定義事件接收方法,方法名稱自定義,使用注解@Subscribe()標示.
@Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(EventBusMsg event) { Log.d(TAG, "接收到信息"); tv_console.setText("EventBus 數(shù)據(jù) : " + event.name); }
- 使用 @Subscribe() 注解來表明這個方法是EventBus事件接收的方法.
- 事件接收方法的參數(shù)必須和EventBus發(fā)送的事件類是同一類型.比如我使用了自己定義的EventBusMsg類.
- 在 @Subscribe() 中可以設置threadMode 來設置不同的模式.關于threadMode下面會有講解,這里使用ThreadMode.MAIN表明這個方法運行在主線程中.
發(fā)布事件
發(fā)布事件比較簡單調用EventBus的post方法即可, 我這里在EventBusSendActivity中發(fā)布事件因此我在EventBusSendActivity的Button的點擊事件中添加如下代碼.
public void sendMsg(View view) {
// 發(fā)送消息
EventBus.getDefault().post(new EventBusMsg("我是EventBus發(fā)送的數(shù)據(jù)"));
// 銷毀當前Activity
finish();
}
到此我們就完成了EventBus的最基本使用 , 我在MainActivity中注冊了事件監(jiān)聽,然后跳轉到EventBusSendActivity 中發(fā)布事件,事件發(fā)布完成后銷毀EventBusSendActivity,此時跳轉到MainActivity中,使用一個TextView打印剛才發(fā)布的時間的name.
注意 : 上面這中用法一定要先訂閱事件在進行發(fā)布事件才可以接收到事件,當然也可以實現(xiàn)先發(fā)布在訂閱的模式,后面會介紹
EventBus 事件回調方法線程(Delivery Thread)
EventBus會處理事件接收線程的問題 , 比如可以將消息發(fā)送到另外一個線程中,比如 : 在 線程A 中發(fā)布事件. 事件傳遞到線程B中執(zhí)行. 這個功能主要用在處理更新UI的問題上,我們都知道在Android中只有在UI線程中才可以更新UI,否則會引發(fā)異常.但是一下耗時操作比如網(wǎng)絡請求等又必須在子線程中執(zhí)行, 此時 EventBus就可以幫助我們處理UI和后臺任務的同步問題 . 就好像Android自帶的Handler 和 Broadcast機制一樣.
EventBus有四種線程模式 , 可以通過@Subscribe()注解的threadMode參數(shù)進行指定.
- ThreadMode : POSTING
POSTING是 threadMode的默認參數(shù),如果不設置該參數(shù)就是POSTING模式. 在這種模式下接收事件的方法和發(fā)布消息的方法運行在同一個線程中.
優(yōu)點 : 這種模式下開銷最小,因為不需要切換線程.
// 運行在發(fā)布消息的線程中 (default)
// ThreadMode 是可選設置
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessage(MessageEvent event) {
log(event.message);
}
- ThreadMode : MAIN
在 MAIN 模式下事件接收方法將會運行在主線程中(有時也稱為UI線程). 如果發(fā)布事件的線程是主線程那么事件就會直接發(fā)布給訂閱者,不會進行線程切換, 也就相當于使用了POSTING模式.
使用注意 : 在此模式不要在事件接收方法中進行耗時操作,防止UI線程阻塞
// 運行在 UI 線程中(主線程)
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
textField.setText(event.message);
}
- ThreadMode : BACKGROUND
事件接收方法將會運行在一個后臺線程中,但是事件不可以并發(fā)執(zhí)行.- 如果發(fā)布事件本身就在后臺線程中,那么事件接收方法就運行在這個線程中,不在另外開啟新的線程.
- 如果發(fā)布事件在主線程中,那么EventBus會開一個后臺線程(只有一個)然后在該線程中依次處理所有事件.
使用注意 : 事件處理方法應當盡快返回,避免阻塞后臺線程.
// 運行在后臺線程中.
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event){
saveToDisk(event.message);
}
- ThreadMode : ASYNC
在ASYNC模式下事件接收方法總是運行在一個發(fā)布事件線程和主線程之外獨立的線程中,發(fā)布事件不必依賴訂閱事件處理結果. 因此此模式適合于在事件處理中有比較耗時的操作的情況.為了避免同一時間有過多的運行線程.EventBus使用線程池和事件處理完成通知來限制最大的線程并發(fā)數(shù).
// 運行在一個獨立的線程中.
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event){
backend.send(event.message);
}
EventBus 高級一點的用法 : 粘性事件(Stick Events)
在EventBus的基本使用中我們說過那種模式必須要先訂閱事件然后再發(fā)布事件. 這次我們來嘗試一下EventBus另一種用法 粘性事件,在這種模式允許先發(fā)布事件再訂閱事件 . EventBus會將粘性事件保存在內存中然后發(fā)送給訂閱者,訂閱者也可以主動查詢粘性事件.
- 定義事件實體類
同樣事件實體類是可以自定義的我這類定義了EventBusStickyMsg實體類.
public class EventBusStickyMsg {
public String name;
public EventBusStickyMsg(String name) {
this.name = name;
}
}
- 發(fā)布粘性事件
發(fā)布粘性事件使用 postSticky() 方法, 我在MainActivity中添加如下代碼.
public void sendStickyEvent(View view) {
EventBus.getDefault().postSticky(new EventBusStickyMsg("我是Sticky消息"));
// 啟動 EventBusSendActivity
Intent intent = new Intent(MainActivity.this, EventBusSendActivity.class);
MainActivity.this.startActivity(intent);
}
- 訂閱粘性事件
訂閱粘性事件和訂閱普通事件是一樣的.都需要進行EventBus的注冊,解注冊以及事件接收函數(shù)- 注冊
public void getStickyMsg(View view) { // 注冊,注意不要進行多次注冊,否則程序可能崩潰.可以設置一個標志. EventBus.getDefault().register(EventBusSendActivity.this); }
注意 : 不要進行重復注冊,可能造成程序崩潰
- 解注冊
@Override
protected void onDestroy() {
super.onDestroy();
// 移除所有的粘性事件.
EventBus.getDefault().removeAllStickyEvents();
// 解注冊
EventBus.getDefault().unregister(EventBusSendActivity.this);
}
- 定義事件接收方法
@Subscribe(sticky = true , threadMode = ThreadMode.MAIN)
public void onStickyEvent(EventBusStickyMsg event) {
tv_console.setText("Sticky 數(shù)據(jù) : " + event.name);
}
粘性事件接收方法需要在@Subscribe()注解中添加sticky = true 參數(shù).
到此粘性事件的使用就完成了. 程序流程大概如下 :
- 在MainActivity中發(fā)布粘性事件.
- 在EventBusSendActivity中注冊事件.
- 在TextView上顯示事件.
上面我們使用的是訂閱方式獲取事件. 我們也可以手動獲取粘性事件,我們添加一個Button在點擊事件中添加如下代碼
public void getStickyMsgManually(View view) {
// 手動獲取粘性事件
EventBusStickyMsg msg = EventBus.getDefault().getStickyEvent(EventBusStickyMsg.class);
if (msg != null) {
tv_console.setText(tv_console.getText().toString() + msg.name);
// 刪除事件
EventBus.getDefault().removeStickyEvent(msg);
}
}
我們首先使用getStickyEvent()方法獲取粘性事件 , 但是我們獲取了該粘性事件后 , EventBus并不會主動刪除該粘性事件,(訂閱方式也不會刪除), 所以我們主動調用了removeStickyEvent() 方法刪除粘性事件.
同時我們通過查看removeStickyEvent()方法返回值可以發(fā)現(xiàn) , 他會將刪除的事件返回,因此我們修改代碼如下.
public void getStickyMsgRemove(View view) {
// 手動獲取粘性事件
EventBusStickyMsg msg = EventBus.getDefault().removeStickyEvent(EventBusStickyMsg.class);
if (msg != null) {
tv_console.setText(tv_console.getText().toString() + msg.name);
}
}
OK 到此關于EventBus的基本使用已經(jīng)介紹完畢,我們主要介紹了一下三點內容 :
- EventBus普通事件的使用方法.
- EvnetBus粘性事件的使用方法.
- EventBus訂閱事件線程模式.
Demo 下載地址 : http://download.csdn.net/detail/qq_16188829/9766568