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框架庫代碼走讀》