概述
EventBus是一個Android事件發佈/訂閱框架,通過解耦發佈者和訂閱者簡化Android事件傳遞,這裏的事件可以理解爲消息。事件傳遞既可以用於Android四大組件間通訊,也可以用於異步線程和主線程間通訊等。
傳統的事件傳遞方式包括:Handler、BroadcastReceiver、Interface回調,相比之下EventBus的有點是代碼簡潔,使用簡單,並將事件發佈和 訂閱充分解耦。
概念
事件Event: 又可成爲消息,其實就是一個對象,可以是網絡請求返回的字符串,也可以是某個開關狀態等等。事件類型EventType是指事件所屬的Class。
事件分爲一般事件和Sticky事件,相對於一般事件,Sticky事件不同之處在於,當事件發佈後,再有訂閱者開始訂閱該類型事件,依然能收到該類型事件的最近一個Sticky事件。
訂閱者Subscriber: 訂閱某種事件類型的對象,當有發佈者發佈這類事件後,EventBus會執行訂閱者的onEvent函數,這個函數叫事件響應函數。訂閱者通過register接口訂閱某個事件類型,unregister接口退訂。訂閱者存在優先級,優先級高的訂閱者可以取消事件繼續向優先級低的訂閱者分發,默認所有訂閱者優先級都爲0。
發佈者Publisher: 發佈某事件的對象,通過post接口發佈事件。
GitHub地址
EventBus源碼:https://github.com/greenrobot/EventBus
基本使用
自定義一個事件類
public class AnyEventType {
public AnyEventType(){}
}
在要接受消息的頁面註冊
EventBus.getDefault().register(this);
接收消息的方法
@Subscribe
public void onEvent(AnyEventType event) {/* Do something */};
發送消息
EventBus.getDefault().post(event);
取消註冊
EventBus.getDefault().unregister(this);
實例
下面我們來實現一個具體的例子來介紹EventBus的基本使用。
需求如下:在MainActivity中註冊EventBus事件,並實現事件響應方法,當點擊MainActivity中的按鈕時跳轉到SecondActivity,當點擊SecondActivity中的按鈕時向MainActivity發送Event事件,當MainActivity收到事件後,將事件內容顯示在TextView中。
-
MainActivity
-
SecondActivity
-
事件處理
事件類Event
public class Event {
private String messgae;
public Event(String messgae) {
this.messgae = messgae;
}
public String getMessgae() {
return messgae;
}
}
MainActivity
在OnCreate()函數中註冊EventBus,在Ondestroy()函數中反註冊。
public class MainActivity extends AppCompatActivity {
@Bind(R.id.btn_open)
Button mOpenBtn;
@Bind(R.id.tv_showinfo)
TextView mInfoTxt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
//註冊
EventBus.getDefault().register(this);
}
/**
* 事件響應方法
* 接收消息
* @param event
*/
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(Event event) {
String msg = event.getMessgae();
mInfoTxt.setText(msg);
}
//綁定點擊事件
@OnClick(R.id.btn_open)
public void openSecondActivity(View view) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
//反註冊
EventBus.getDefault().unregister(this);
}
}
SecondActivity
public class SecondActivity extends AppCompatActivity {
@Bind(R.id.btn_post)
Button mPostBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
ButterKnife.bind(this);
mPostBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
//發送事件
EventBus.getDefault().post(new Event("Just do it"));
}
}).start();
}
});
}
}
EventBus的事件訂閱函數
類別
在上面的例子中,我們再註解@Subscribe(threadMode = ThreadMode.MAIN)
中使用了ThreadMode.MAIN這個模式,表示該函數在主線程即UI線程中執行,實際上EventBus總共有四種線程模式,分別是:
-
ThreadMode.MAIN:表示無論事件是在哪個線程發佈出來的,該事件訂閱方法onEvent都會在UI線程中執行,這個在Android中是非常有用的,因爲在Android中只能在UI線程中更新UI,所有在此模式下的方法是不能執行耗時操作的。
-
ThreadMode.POSTING:表示事件在哪個線程中發佈出來的,事件訂閱函數onEvent就會在這個線程中運行,也就是說發佈事件和接收事件在同一個線程。使用這個方法時,在onEvent方法中不能執行耗時操作,如果執行耗時操作容易導致事件分發延遲。
-
ThreadMode.BACKGROUND:表示如果事件在UI線程中發佈出來的,那麼訂閱函數onEvent就會在子線程中運行,如果事件本來就是在子線程中發佈出來的,那麼訂閱函數直接在該子線程中執行。
-
ThreadMode.AYSNC:使用這個模式的訂閱函數,那麼無論事件在哪個線程發佈,都會創建新的子線程來執行訂閱函數。
實戰
如何調用不同的訂閱函數
要調用四種不同模式的訂閱函數,我們首先要用清楚EventBus是如何指定調用的函數的?
先回顧一下上一節中的例子是如何調用訂閱函數onEvent的,首先新建一個事件類:
public class Event {
private String messgae;
public Event(String messgae) {
this.messgae = messgae;
}
public String getMessgae() {
return messgae;
}
}
發佈事件:
EventBus.getDefault().post(new Event("Just do it"));
訂閱事件:
/**
* 事件響應方法
* @param event
*/
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMain(Event event) {
String msg = event.getMessgae();
mInfoTxt.setText(msg);
}
觀察可以發現:發佈事件中的參數是Event的實例,而訂閱函數中的參數也是Event的實例,可以推斷EventBus是通過post函數傳進去的類的實例來確定調用哪個訂閱函數的,是哪個就調用哪個,如果有多個訂閱函數呢,那麼這些函數都會被調用!
示例
下面我們來驗證這個推斷:
我們在基本使用章節的例子上進行擴展,首先建立四個類:FirstEvent、SecondEvent、ThirdEvent、FourthEvent。
FirstEvent.java
public class FirstEvent {
private String messgae;
public FirstEvent(String messgae) {
this.messgae = messgae;
}
public String getMessgae() {
return messgae;
}
}
SecondEvent.java
public class SecondEvent {
private String messgae;
public SecondEvent(String messgae) {
this.messgae = messgae;
}
public String getMessgae() {
return messgae;
}
}
ThirdEvent.java
public class ThirdEvent {
private String messgae;
public ThirdEvent(String messgae) {
this.messgae = messgae;
}
public String getMessgae() {
return messgae;
}
}
FourthEvent.java
public class FourthEvent {
private String messgae;
public FourthEvent(String messgae) {
this.messgae = messgae;
}
public String getMessgae() {
return messgae;
}
}
然後在MainActivity中,增加四種模式的訂閱函數
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Bind(R.id.btn_open)
Button mOpenBtn;
@Bind(R.id.tv_showinfo)
TextView mInfoTxt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
//註冊
EventBus.getDefault().register(this);
}
/**
* 事件響應方法
* @param event
*/
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMain(FirstEvent event) {
String msg = event.getMessgae();
Log.i(TAG, "onEventMain: " + event.getMessgae());
}
@Subscribe(threadMode = ThreadMode.POSTING)
public void onEventPosting(SecondEvent event) {
String msg = event.getMessgae();
Log.i(TAG, "onEventPosting: "+ event.getMessgae());
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onEventBackgroud(ThirdEvent event) {
String msg = event.getMessgae();
Log.i(TAG, "onEventBackgroud: " + event.getMessgae());
}
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onEventAsync(FourthEvent event) {
String msg = event.getMessgae();
Log.i(TAG, "onEventAsync: " + event.getMessgae());
}
//綁定點擊事件
@OnClick(R.id.btn_open)
public void openSecondActivity(View view) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
//反註冊
EventBus.getDefault().unregister(this);
}
}
接下來在SecondActivity中增加四個按鈕,分別發送不同類別的事件
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
ButterKnife.bind(this);
}
@OnClick(R.id.btn_post)
public void onPostA() {
EventBus.getDefault().post(new FirstEvent("FirstEvent"));
}
@OnClick(R.id.btn_post2)
public void onPostB() {
EventBus.getDefault().post(new SecondEvent("SecondEvent"));
}
@OnClick(R.id.btn_post3)
public void onPostC() {
EventBus.getDefault().post(new ThirdEvent("ThirdEvent"));
}
@OnClick(R.id.btn_post4)
public void onPostD() {
EventBus.getDefault().post(new FourthEvent("FourthEvent"));
}
}
運行後,分別順序點擊SecondActivity的四個按鈕,打印信息如下:
03-31 02:53:45.950 4779-4779/com.example.michael.eventbusdemo I/MainActivity: onEventMain: FirstEvent
03-31 02:53:47.528 4779-4779/com.example.michael.eventbusdemo I/MainActivity: onEventPosting: SecondEvent
03-31 02:53:48.882 4779-4940/com.example.michael.eventbusdemo I/MainActivity: onEventBackgroud: ThirdEvent
03-31 02:53:50.462 4779-4940/com.example.michael.eventbusdemo I/MainActivity: onEventAsync: FourthEvent
由此可見,通過發佈不同的事件類的實例,EventBus根據類的實例分別調用了不同的訂閱函數來處理事件。
那麼,當同一個類的實例有多個函數訂閱時,結果會是怎樣呢?答案是,這些函數都會執行。下面我們來驗證一下,將MainActivity中訂閱函數的參數都改爲FirstEvent,代碼如下:
/**
* 事件響應方法
* @param event
*/
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMain(FirstEvent event) {
String msg = event.getMessgae();
Log.i(TAG, "onEventMain: " + event.getMessgae());
}
@Subscribe(threadMode = ThreadMode.POSTING)
public void onEventPosting(FirstEvent event) {
String msg = event.getMessgae();
Log.i(TAG, "onEventPosting: "+ event.getMessgae());
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onEventBackgroud(FirstEvent event) {
String msg = event.getMessgae();
Log.i(TAG, "onEventBackgroud: " + event.getMessgae());
}
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onEventAsync(FirstEvent event) {
String msg = event.getMessgae();
Log.i(TAG, "onEventAsync: " + event.getMessgae());
}
運行程序,點擊SecondActivity的FirstEvent按鈕,打印信息如下:
03-31 03:14:07.032 23611-23746/com.example.michael.eventbusdemo I/MainActivity: onEventAsync: FirstEvent
03-31 03:14:07.033 23611-23611/com.example.michael.eventbusdemo I/MainActivity: onEventMain: FirstEvent
03-31 03:14:07.033 23611-23611/com.example.michael.eventbusdemo I/MainActivity: onEventPosting: FirstEvent
03-31 03:14:07.034 23611-23748/com.example.michael.eventbusdemo I/MainActivity: onEventBackgroud: FirstEvent
分析可知,當SecondActivity發送FirstEvent事件過來的時候,這個四個訂閱函數會同時接收到這個事件並執行。
總結: 訂閱函數的執行是根據參數中的事件類的類名來決定的。
參考: