一、背景介紹
在編程過程中,當我們想通知其他組件某些事情發生時,我們通常使用觀察者模式,正是因爲觀察者模式非常常見,所以在jdk1.5中已經幫助我們實現了觀察者模式,我們只需要簡單的繼承一些類就可以快速使用觀察者模式,在Android中也有一個類似功能的開源庫EventBus。 此篇幅主要講述EventBus是什麼?EventBus可以幫助我們幹些什麼?還有EventBus是怎樣調用的?下一篇幅將會對EventBus的源碼進行解讀,分析EventBus框架結構,工作原理等,敬請關注。
二、EventBus簡介
對於Android開發人員來講,跨線程通信,多個Activity通信,服務和UI通信,組件之間的通信等,並不陌生,Android系統給我們提供了很多便捷的方法,例如廣播,Handler,方法回調等。在GitHut上有這麼一個開源庫EventBus,他很好的解決了以上所述場景的通信,並提供了簡化,易懂,低耦合的架構API。
- 什麼是EventBus
EventBus其實是利用了這麼一個概念,以發佈者和訂閱者的角色,描述和處理事件的傳遞,事件傳遞之間帶有事件屬性(即數據)。而且這個角色是可以進行對調的,一個發佈者可以去發佈事件也可以接受事件,一個訂閱者可以訂閱多個事件也可以發佈事件,這樣就形成了事件池的事件分發機制,所有發佈者發佈的事件被存儲在對應EventBus的事件池中,所有訂閱者根據自己的需要往事件池裏註冊要訂閱的事件,當事件池中有事件進來時,EventBus會根據事件分發原則把事件分發到訂閱者去處理。 - EventBus能做什麼,怎麼調用
首先EventBus是一個開源框架,此框架主要是建立事件分發和訂閱的。用來簡化應用組件之間的通信,替代傳統通信模式:廣播,Handler,方法回調,而生的一個輕量級的通信架構,使用者只需要進行註冊,訂閱,發佈,取消訂閱,這幾個簡單的操作既可以完成不同組件之間的通信交流和數據傳輸。在實際應用開發中,我們總是希望把耗時複雜的工作交給service去處理,在UI組件中只關心結果的展示和用戶的交互。在EventBus沒出來前,我們可能想到最多的方法可能就是廣播,Handler線程通信等等方法來解決,但是無可否認這些傳統的處理方法有時候太過於繁瑣,而EventBus能更好,更簡潔地幫我們解決這些繁瑣的問題。至於EventBus怎麼調用?下面我們由Demo來講解。
Demo講解
例如我們要做一個計時器,希望服務端每一秒通知一下UI端去更新時間信息這麼一個需要求。在傳統模式下,我們可能需要綁定服務,在服務中調用UI組件進行更新視圖,又或者建立回調方法進行通知變更。那麼在EventBus中,我們是怎樣處理的呢?
- 引入EventBus開源庫
- 註冊到EventBus
- 訂閱事件
- 發佈事件
- 反註冊EventBus
下面結合Demo的代碼進行分析:
先在gradle中添加依賴:
compile 'org.greenrobot:eventbus:3.0.0'
接着看看核心代碼:
public class MainActivity extends Activity {
private TextView time;
private Intent tS;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
time = (TextView) findViewById(R.id.time);
EventBus.getDefault().register(this);
tS = new Intent(this, TimeService.class);
startService(tS);
}
public void onEventMainThread(TimeEvent event) {
int h = 0, m = 0, s = 0;
int t = event.getTime();
if (t >= 86400) {
time.setText("24:00:00+");
} else {
if (t >= 3600) {
h = t / 3600;
t = t % 3600;
}
if (t >= 60) {
m = t / 60;
t = t % 60;
}
s = t;
time.setText(h + ":" + m + ":" + s);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
stopService(tS);
}
}
- 要接收事件,那麼先要有訂閱者,在此示例中訂閱者就是主Activity本身,我們要把它註冊到EventBus中
EventBus.getDefault().register(this);
通過以上這麼一行代碼,我們就完成了訂閱者的註冊,這裏默認註冊到默認的EventBus當中,也可以通過其他API建立不同的EventBus對象,每個EventBus對象的事件是互不干擾分發的
- 完成註冊後,我們要進行事件的訂閱,要有事件的訂閱,就必須有對應Type的事件,也就是常說的EventModel
public class TimeEvent {
private int time = 0;
public int getTime(){
return time;
}
public void setTime(int t){
time = t;
}
}
由於我們是要做一個計時器,那麼事件我們就定義爲一個TimeEvent,裏面返回秒數信息就可以了。訂閱事件其實就是在訂閱者中增加以OnEvent開頭的public類型的函數方法:
public void onEventMainThread(TimeEvent event) {
int h = 0, m = 0, s = 0;
int t = event.getTime();
if (t >= 86400) {
time.setText("24:00:00+");
} else {
if (t >= 3600) {
h = t / 3600;
t = t % 3600;
}
if (t >= 60) {
m = t / 60;
t = t % 60;
}
s = t;
time.setText(h + ":" + m + ":" + s);
}
}
對應的參數是唯一的時間類型對象,OnEventXXX有幾種時間Mode,分別對應PostThread,MainThread,BackgroundThread,Async根據字面意思也很好理解他們分別在那個線程進行工作處理的,默認爲PostThread模式,以上我們接受到TimeEvent時,做了一件事件就是在主線程中根據返回的event中的秒數,進行更新UI組件TextView,進行顯示。
3.有了訂閱者,有了訂閱時間,我們就需要一個發佈者和發佈事件的流程,我們完成計數的操作是早Service中完成的。
public class TimeService extends Service {
private Thread mTime;
private TimeEvent mTimeEvent;
public TimeService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
mTimeEvent = new TimeEvent();
mTime = new Thread(new Runnable() {
@Override
public void run() {
while(true) {
mTimeEvent.setTime(mTimeEvent.getTime() + 1);
EventBus.getDefault().post(mTimeEvent);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
mTime.start();
}
@Override
public void onDestroy() {
super.onDestroy();
mTime.stop();
mTime.destroy();
mTime = null;
}
}
服務開啓時,我們啓了一個線程進行每秒的計數,並通過:
EventBus.getDefault().post(mTimeEvent);
把事件結果發佈到EventBus中分發處理,EventBus會根據已有的訂閱者,調度對應的OnEventXX通過訂閱者事件結果。
4.當我們一旦不需要訂閱了,我們可以通過反註冊取消
EventBus.getDefault().unregister(this);