EventBus3.0事件介紹
EventBus是一個基于觀察者模式,并且是針對了Android進行優化的釋出/訂閱的事件總線。簡化了應用程式内各元件間、元件與背景線程間的通信。優點是開銷小,代碼更優雅,以及将發送者和接收者解耦,避免了産生大量的内部類。
EventBus3.0應用的範圍比較廣,比如請求網絡,當請求網絡後,可以通過handler和broadcast通知UI,同樣也可以使用EventBus3.0實作。Activity和Activity進行互動還好說,如果Fragment和Fragment進行互動着實令人頭疼,我們會使用廣播來處理,但是使用廣播稍顯麻煩并且效率也不高,如果傳遞的資料是實體類需要序列化,那麼很顯然成本會有點高。
是以在涉及Activity與Fragment之間,Fragment與Fragment之間進行互動的時候,優先考慮使用EventBus3.0進行通信。關于EventBus3.0更多的介紹可以參考EventBus官方介紹:
EventBus3.0的三大要素
講述eventBus的工作流程,可以先看下官網給出的關系圖

官網提供的關系圖
事件的釋出者Publisher通過post事件,将具體的事件通知給事件的訂閱者Subscriber,然後在由訂閱者對接收到的事件進行處理。
Event:事件
可以是任意類型的資料,比如簡單的string類型的擷取;
public class updateTextEvent {
private static final String TAG = "AA";
private String msg;
public updateTextEvent(String msg) {
this.msg = msg;
Log.i(TAG, "updateTextEvent: " + msg);
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
Publisher:事件釋出者
可以在任意線程任意位置發送事件,直接調用EventBus的post(Object)方法。可以自己執行個體化EventBus對象,但一般使用EventBus.getDefault()就好了,根據post函數參數的類型,會自動調用訂閱相應類型事件的函數。
Subsriber:事件訂閱者
在EventBus3.0之前的EventBus1.0和EventBus2.0時代消息處理的方法隻能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,他們分别代表四種線程模型。而在EventBus3.0之後,事件處理的方法可以随便取名,但是需要添加一個注解@Subscribe,并且要指定線程模型(預設為POSTING)。例:
@Subscribe(threadMode = ThreadMode.MAIN)
public void modifyBtn4(updateTextEvent msg){
button.setText(msg.getMsg());
}
綜合上述的流程及對于其中重要的三個元素的認識,可以認為在使用EventBus3.0總共分為以下幾個步驟:
前提:
在Android studio的module的build.gradle中配置編譯庫連接配接:目前最新的版本為3.1.1
compile 'org.greenrobot:eventbus:3.1.1'
事件的定義
public static class MessageEvent {
}
事件訂閱者的準備
聲明并且采用注解的方式來定義訂閱者的方法,預設的情況下,注解方法中的threadMode為MAIN,表示在主線程中運作,事件處理的函數名可以自行定義。下面會講述4中線程的模式。
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
};
事件的釋出者的準備
事件釋出者的工作相對比較簡單,最常用的是采用post或者postSticky的方法,将new出來的事件對象釋出出來,這兩種釋出的方法,将會在下面知識讨論中進行講述其差別。
EventBus.getDefault().post(new MessageEvent());
那麼問題來了,時間的訂閱者如何才能得知有事件被釋出了呢?是以在使用EventBus3.0的時候需要在事件訂閱的那個activity或者fragment中進行注冊,其注冊代碼的地方依附于activity或者fragment的生命周期,即:
@Override
public void onStart() {
super.onStart();
//在事件被訂閱的界面中注冊EventBus
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
//登出EventBus
EventBus.getDefault().unregister(this);
}
EventBus的四種線程模型---ThreadMode
在講述事件訂閱者的時候,采用添加注解的方法@Subscribe(threadMode = ThreadMode.MAIN)對事件的處理進行差別,檢視EventBus3.0線程模型文檔,有以下幾種線程模型,來幫助開發者針對不同的事件,和事件消費類型進行選擇。
ThreadMode: POSTING
預設的線程模式,如果使用事件處理函數指定了線程模型為POSTING,那麼該事件在哪個線程釋出出來的,事件處理函數就會在這個線程中運作,也就是說釋出事件和接收事件在同一個線程。此外,線上程模型為POSTING的事件處理函數中盡量避免執行耗時操作,因為它會阻塞事件的傳遞,甚至有可能會引起ANR。
ThreadMode: MAIN
事件的處理會在UI線程中執行。此外也不能在處理事件中執行比較耗時的操作,否則也會引起ANR。
ThreadMode: BACKGROUND
如果事件是在UI線程中釋出出來的,那麼該事件處理函數就會在新的線程中運作,如果事件本來就是子線程中釋出出來的,那麼該事件處理函數直接在釋出事件的線程中執行。在此事件處理函數中禁止進行UI更新操作。
ThreadMode: ASYNC
無論事件在哪個線程釋出,該事件處理函數都會在建立的子線程中執行,同樣,此事件處理函數中禁止進行UI更新操作,因為這牽涉到UI的更新隻能在 main thread中更新。
在通過學習并了解了上面的EventBus3.0的相關知識後,可以進行一些資料的通信了。按照EventBus3.0的三大要素,分别進行操作實作資料的通信。
首先添加庫依賴
//ButterKnife控件綁定依賴
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
//EventBus控件綁定
compile 'org.greenrobot:eventbus:3.1.1'
事件
public class updateTextEvent {
private static final String TAG = "AA";
private String msg;
public updateTextEvent(String msg) {
this.msg = msg;
Log.i(TAG, "updateTextEvent: " + msg);
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
事件的訂閱者及事件的訂閱者
public class MainActivity extends AppCompatActivity {
private static final String TAG = "AA";
@BindView(R.id.button1)
Button button1;
@BindView(R.id.button2)
Button button2;
@BindView(R.id.button3)
Button button3;
@BindView(R.id.button4)
Button btn4;
@BindView(R.id.button5)
Button button5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注冊ButterKnife
ButterKnife.bind(this);
//注冊EventBus
EventBus.getDefault().register(this);
}
//添加對于button 按鈕事件的注解
@OnClick({R.id.button1, R.id.button2, R.id.button3, R.id.button4, R.id.button5})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.button1:
Toast.makeText(this,"開始",Toast.LENGTH_SHORT).show();
break;
case R.id.button2:
// EventBus.getDefault().postSticky(new updateTextEvent("這是一個測試"));
EventBus.getDefault().post(new updateTextEvent("這是一個測試"));
// Intent intent = new Intent(this,SecActivity.class);
// startActivity(intent);
break;
case R.id.button3:
break;
case R.id.button4:
break;
case R.id.button5:
break;
}
}
//更改button4的文本内容
@Subscribe(threadMode = ThreadMode.MAIN)
public void modifyBtn4(updateTextEvent msg){
// list.get(3).setText(msg.getMsg());
btn4.setText(msg.getMsg());
}
@Override
protected void onDestroy() {
super.onDestroy();
//登出EventBus
EventBus.getDefault().unregister(this);
}
}
細心的讀者應該也注意到了在上述MainActivity中,使用到了Jake Whaton大神的butterknife的使用。測試結果如下,可以正常的進行資料的通信。

Activity測試通信OK
按照上面的事件釋出及訂閱事件,在同一個activity中進行事件的通信是沒有問題的,那如果按下上述的button2,能否将這個事件釋出通知到其他activity中的訂閱者呢?建立一個SecActivity,代碼如下:
public class SecActivity extends AppCompatActivity {
@BindView(R.id.textview)
TextView text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sec);
ButterKnife.bind(this);
EventBus.getDefault().register(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void cha(updateTextEvent msg){
text.setText(msg.getMsg());
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
同時在修改MainActivity中的代碼,注釋掉EventBus的注冊和登出代碼。
//EventBus.getDefault().register(this);
//EventBus.getDefault().unregister(this);
并且添加activity的跳轉代碼,當按下button2的時候,正常跳轉到SecActivity,但是并沒有預期的修改text的現象,查詢log如下,提示并沒有注冊訂閱者。
11-23 07:55:43.599 6286-6286/com.example.myapplication D/EventBus: No subscribers registered for event class org.greenrobot.eventbus.NoSubscriberEvent
--------- beginning of system
11-23 07:55:43.652 6286-6325/com.example.myapplication D/EGL_emulation: eglMakeCurrent: 0xaa7c7240: ver 2 0 (tinfo 0xaa7e00a0)
11-23 07:55:43.653 6286-6325/com.example.myapplication D/EGL_emulation: eglMakeCurrent: 0xaa7c7240: ver 2 0 (tinfo 0xaa7e00a0)
理清思路,事件的釋出和訂閱是與activity的生命周期有關系的,如何解決這個問題呢?還記得上面講述的postSticky()方法嗎?
查詢這個這個文檔:Sticky Events的官方文檔,意譯為:先釋出事件,然後在訂閱。
是以修改MainActivity中post代碼為:
EventBus.getDefault().postSticky(new updateTextEvent("這是一個測試"));
與此同時,也需要修改SecActivity的代碼:
public class SecActivity extends AppCompatActivity {
@BindView(R.id.textview)
TextView text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sec);
ButterKnife.bind(this);
EventBus.getDefault().register(this);
}
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void cha(updateTextEvent msg){
text.setText(msg.getMsg());
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
測試結果如下圖:

image.png
至此,EventBus3.0的常用方法及使用的說明,開發者應該有了基本的認識了。愉快的coding吧。
EventBus3.0的釋出及廣泛的應用已經有很長時間了,文中部分内容參考借鑒了其他開發者的部落格内容:
非常感謝簡書提供的這個知識彙聚分享的平台。