目錄
1. EventBus 框架
EventBus,顧名思義即事件總線,是針對Android跨進程、線程通信的優化方案,在一定程度上可以代替Handle、Intent、Brodcast等實現通信;如下圖所示即EventBus的運行框架。
在EventBus中主要有以下三個成員:
- Event:事件,可以自定義爲任意對象,類似Message類的作用;
- Publisher:事件發佈者,可以在任意線程、任意位置發佈Event,已發佈的Evnet則由EventBus進行分發;
- Subscriber:事件訂閱者,接收並處理事件,需要通過register(this)進行註冊,而在類銷燬時要使用unregister(this)方法解註冊。每個Subscriber可以定義一個或多個事件處理方法,其方法名可以自定義,但需要添加@Subscribe的註解,並指明ThreadMode(不寫默認爲Posting)。
1.1 五種ThreadMode
- Posting:直接在事件發佈者所在線程執行事件處理方法;
- Main:直接在主線程中執行事件處理方法(即UI線程),如果發佈事件的線程也是主線程,那麼事件處理方法會直接被調用,並且未避免ANR,該方法應避免進行耗時操作;
- MainOrdered:也是直接在主線程中執行事件處理方法,但與Main方式不同的是,不論發佈者所在線程是不是主線程,發佈的事件都會進入隊列按事件串行順序依次執行;
- BACKGROUND:事件處理方法將在後臺線程中被調用。如果發佈事件的線程不是主線程,那麼事件處理方法將直接在該線程中被調用。如果發佈事件的線程是主線程,那麼將使用一個單獨的後臺線程,該線程將按順序發送所有的事件。
- Async:不管發佈者的線程是不是主線程,都會開啓一個新的線程來執行事件處理方法。如果事件處理方法的執行需要一些時間,例如網絡訪問,那麼就應該使用該模式。爲避免觸發大量的長時間運行的事件處理方法,EventBus使用了一個線程池來有效地重用已經完成調用訂閱者方法的線程以限制併發線程的數量。
後面會通過代碼展示五種ThreadMode的工作方式。
2. EventBus的使用流程
1. build.gradle 中添加EventBus的依賴:
dependencies {
...
compile 'org.greenrobot:eventbus:3.1.1'
}
2. 定義Event事件類:
public class myEvent {
private String mMessage;
...
}
3. 添加訂閱事件:
EventBus.getDefault().register(this);
4. 定義事件處理方法並添加註解,參數爲定義的事件類:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(myEvent me){
...
}
5. 發佈事件以觸發事件處理方法:
EventBus.getDefault().post(new myEvent("this is first message !"));
3. EventBus應用
以下Demo以5中不同的ThreadMode定義了5個事件處理方法,並新開啓一個線程作爲事件發佈者。
3.1 定義Event時間類
/**
* Created by wise on 2018/5/16.
*/
/**Event事件類**/
public class myEvent {
private String mMessage;
public myEvent(String message){
this.mMessage = message;
}
public void setMessage(String message){
this.mMessage = message;
}
public String getmessage(){
return this.mMessage;
}
}
3.2 EventBus功能實現
public class EventBusActivity extends AppCompatActivity {
private static final String TAG = "EventBusActivity";
private TextView tv_Event;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_bus);
/**註冊事件**/
EventBus.getDefault().register(this);
Thread thread1 = new Thread(new myThread1());
thread1.start();
}
/**事件處理方法**/
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMain(myEvent me){
Log.d(TAG,me.getmessage() + " onEventMain" + " thread:" + android.os.Process.myTid());
}
/**事件處理方法**/
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onEventMainOrdered(myEvent me){
Log.d(TAG,me.getmessage() + " onEventMainOrdered" + " thread:" + android.os.Process.myTid());
}
/**事件處理方法**/
@Subscribe(threadMode = ThreadMode.POSTING)
public void onEventPosting(myEvent te){
Log.d(TAG,te.getmessage() + " onEventPosting" + " thread:" + android.os.Process.myTid());
}
/**事件處理方法**/
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onEventBackground(myEvent me){
Log.d(TAG,me.getmessage() + " onEventBackground" + " thread:" + android.os.Process.myTid());
}
/**事件處理方法**/
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onEventAsync(myEvent me){
Log.d(TAG,me.getmessage() + " onEventAsync" + " thread:" + android.os.Process.myTid());
}
@Override
protected void onDestroy() {
super.onDestroy();
/**解註冊**/
EventBus.getDefault().unregister(this);
}
public class myThread1 implements Runnable {
@Override
public void run() {
Log.d(TAG,"" + android.os.Process.myTid());
try {
Thread.sleep(1000);
/**事件發佈**/
EventBus.getDefault().post(new myEvent("this is first message !"));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
執行結果如下:
05-24 17:17:47.335 24447 24478 D EventBusActivity: 24478
05-24 17:17:48.341 24447 24478 D EventBusActivity: this is first message ! onEventBackground thread:24478
05-24 17:17:48.341 24447 24498 D EventBusActivity: this is first message ! onEventAsync thread:24498
05-24 17:17:48.342 24447 24447 D EventBusActivity: this is first message ! onEventMain thread:24447
05-24 17:17:48.342 24447 24447 D EventBusActivity: this is first message ! onEventMainOrdered thread:24447
05-24 17:17:48.344 24447 24478 D EventBusActivity: this is first message ! onEventPosting thread:24478
主線程Tid爲24447,子線程Tid爲24478,可以看到每種ThreadMode的運行方式。另外我們可以通過定義不同的事件類作爲post的參數來執行不同的事件執行方法,後一篇會分析源碼解釋調用事件處理方法的邏輯。
4. EventBus的粘性事件
以上的Demo中,事件訂閱者的註冊必須在發佈事件之前,否則發佈之後,訂閱者無法接受到事件,而粘性事件則避免了這一問題,粘性事件的發佈使用postSticky()方法即可,並在註解中配置sticky參數。
// 訂閱粘性事件
@Subscribe(sticky = true)
public void onMessageEvent(myEvent me) {
...
}
// 粘性事件發佈
EventBus.getDefault().postSticky(new myEvent ("This is sticky event"));
發佈一個粘性事件之後,EventBus將在內存中緩存該粘性事件。當有訂閱者訂閱了該粘性事件,訂閱者將接收到該事件。需要注意的是在未移除粘性事件之前,它會一直緩存在內存中,因此在處理完該事件後要及時移除該事件的緩存,移除粘性事件的方法如下:
// 移除指定的粘性事件
removeStickyEvent(Object event);
// 移除指定類型的粘性事件
removeStickyEvent(Class<T> eventType);
// 移除所有的粘性事件
removeAllStickyEvents();
5. EventBus中的優先級
在定義事件處理方法時,還可以在註解中設置該方法的優先級:
@Subscribe(priority = 1)
public void onEvent(myEvent me) {
...
}
默認情況下,訂閱者方法的事件傳遞優先級爲0。數值越大,優先級越高。在相同的線程模式下,更高優先級的訂閱者方法將優先接收到事件。注意:優先級只有在相同的線程模式下才有效。