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