EventBus使用之基礎
PS一句:最終還是選擇CSDN來整理發表這幾年的知識點,該文章平行遷移到CSDN。因為CSDN也支持MarkDown語法了,牛逼啊!
【工匠若水 http://blog.csdn.net/yanbober】
開源項目鏈接
EventBus項目:https://github.com/greenrobot/EventBus
EventBusDemo下載:https://github.com/yanbober/Android-Blog-Source/tree/master/Android-EventBus-Demo
背景介紹
如果你學習過設計模式,那么當想通知其他組件某些事情發生時你一定會使用觀察者模式。好了,既然能想到這個設計模式,那么就來看一個屌爆天的Android開源框架EventBus。主要功能是替代Intent、Handler、BroadCast在Fragment、Activity、Service、線程之間傳遞消息。他的最牛逼優點是開銷小,代碼簡潔,解耦代碼。
基礎介紹
上面說了,EventBus是一個觀察者模式的實現,既然這樣,那他就有如下三個要素:
- Event:事件
- Subscriber:事件訂閱者,接收特定的事件。
- Publisher:事件發布者,用于通知Subscriber有事件發生。
其中,Event可以使任意類型對象。Subscriber都是以約定的onEvent開頭的函數,具體是onEvent,onEventMainThread,onEventBackgroundThread,onEventAsync這四個。Publisher可以通過post(Object)在任意線程任意位置發送事件。
官方這個圖就很直觀的說明了這種觀察者模式的架構:

依據開源庫組件的說明文檔來操作:
- 在工程gradle中添加:compile ‘de.greenrobot:eventbus:2.4.0’。
- 按照文檔HOWTO.md進行操作。
Subscriber以onEvent開頭的4個函數區別:
-
onEvent:事件的處理在和事件的發送在相同的線程,所以事件處理時間不應太長,不然影響事件的發送線程。
-
onEventMainThread: 事件的處理會在UI線程中執行。事件處理時間不能太長,長了會出現臭名遠之的ANR。
-
onEventBackgroundThread:事件的處理會在一個后臺線程中執行。雖然名字是BackgroundThread,事件處理是在后臺線程,但事件處理時間還是不應該太長,因為如果發送事件的線程是后臺線程,會直接在當前后臺線程執行事件;如果當前線程是UI線程,事件會被加到一個隊列中,由一個線程依次處理這些事件,如果某個事件處理時間太長,會阻塞后面的事件的派發或處理。
-
onEventAsync:事件處理會在單獨的線程中執行,主要用于在后臺線程中執行耗時操作,每個事件會開啟一個線程,但最好限制線程的數目。
下面還是先上代碼再總結分析。
實戰一把屌爆天的功能
如下示例演示了EventBus的線程間通信與線程內通信及自定義消息結構的通信。
如下是主界面顯示效果:

接著看代碼:
首先自定義一個消息數據類型,如下:
public class MsgBean {
private String msg;
public MsgBean(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
} 接著編寫主界面及邏輯代碼:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView mShowInfo1, mShowInfo2, mShowInfo21, mShowInfo22;
private Button mBtn1, mBtn2, mBtn21, mBtn22;
private int mCount = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
}
private void initData() {
mShowInfo1 = (TextView) findViewById(R.id.first_show);
mBtn1 = (Button) findViewById(R.id.get_btn_1);
mBtn1.setOnClickListener(this);
mShowInfo2 = (TextView) findViewById(R.id.second_show);
mBtn2 = (Button) findViewById(R.id.get_btn_2);
mBtn2.setOnClickListener(this);
mShowInfo21 = (TextView) findViewById(R.id.first_show_lin2);
mBtn21 = (Button) findViewById(R.id.get_btn_1_line2);
mBtn21.setOnClickListener(this);
mShowInfo22 = (TextView) findViewById(R.id.second_show_line2);
mBtn22 = (Button) findViewById(R.id.get_btn_2_line2);
mBtn22.setOnClickListener(this);
}
@Override
protected void onStart() {
super.onStart();
//注冊EventBus
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
//取消EventBus
EventBus.getDefault().unregister(this);
}
//事件1接收者:在主線程接收
public void onEvent(String event){
mShowInfo1.setText(event);
}
//事件2接收者:在主線程接收自定義MsgBean消息
public void onEvent(MsgBean event){
mShowInfo21.setText(event.getMsg());
}
//事件3接收者:在主線程接收
public void onEventMainThread(Integer event) {
mShowInfo2.setText(event+"");
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.get_btn_1:
//事件1發送者:在主線程發送
EventBus.getDefault().post("test!");
break;
case R.id.get_btn_1_line2:
//事件2發送者:在主線程發送自定義MsgBean消息
EventBus.getDefault().post(new MsgBean("type"));
break;
case R.id.get_btn_2:
//事件3發送者:在子線程循環發送
new Timer().schedule(new TimerTask() {
@Override
public void run() {
EventBus.getDefault().post(mCount);
if (mCount >= 3) {
this.cancel();
mCount = 0;
}
mCount++;
}
}, 0, 1000);
break;
}
}
} xml代碼太簡單就省略了。
如下運行結果:

從上面代碼可以看見,當發過來一個消息的時候,EventBus區分onEventxxx被調運通過發送消息的參數類型區分(如:post(new MsgBean(“type”))對應onEvent(MsgBean event),post(“test!”)對應onEvent(String event))。
總結
通過上面基礎實戰發現,使用EventBus的基本步驟就是如下4步:
- 定義事件類型(或者不定義)。例如:MsgBean等
- 定義事件處理方法。例如:onEvent等
- 注冊訂閱者。例如:EventBus.getDefault().register(this)
- 發送事件。例如:EventBus.getDefault().post(new MyEvent())
通過這個例子基本上你就可以上手EventBus框架使用了,也知道了大致基本原理。其實這還是不夠,玩意出現bug又很郁悶不知道怎么改,所以下一篇還是老規矩,走讀一下EventBus的大致源碼,學習下作者的代碼思想,同時熟悉EventBus的原理。
【工匠若水 http://blog.csdn.net/yanbober】
繼續閱讀本系列下一篇《EventBus框架庫代碼走讀》