原理
這是官方的一張圖片說明,很能說明問題,畢竟官方是最權威的
Android傳統的Intent,Handler,Broadcast或接口函數,在Fragment,Activity,Service線程之間傳遞數據,執行方法,這樣做消息的發送者和接收者之間耦合就很高,
EventBus可以替代它們,將發佈者和接收者(也說是訂閱者)之間分離,
通過解耦發佈者和訂閱者簡化Android事件傳遞
說白了EventBus就是 觀察者設計模式。
使用步驟:
1. 將EventBus導入項目
Gradle 依賴 compile 'org.greenrobot:eventbus:3.0.0'
2. 定義事件-也就是傳遞的數據
(也就是一個沒有任何特別要求的Java實體類)
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
2. 準備觀察者(也就是消息的接收者)
- 觀察者需要實現事件處理方法,當事件消息被髮送時,此方法將會被調用。
// This method will be called when a MessageEvent is posted (in the UI thread for Toast)
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
// This method will be called when a SomeOtherEvent is posted
@Subscribe
public void handleSomethingElse(SomeOtherEvent event) {
doSomethingWith(event);
}
- 觀察者必須先要註冊才能接收事件event(註銷),在activity和fragment中,可以根據生命週期來註冊和註銷EventBus.
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
3. 發送消息事件
你可以在任何地方發送消息,所有的已經註冊的、並且匹配消息事件類型的觀察者(消息接收者)都會收到該事件
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
注意:在寫接收消息的方法是,方法名可以自定義,權限必須是public,參數必須是一個只要接收的參數類型是一致的,那麼四個方法都可以接收到發送的信息
事件分發的線程:
處理多線程問題
1. ThreadMode.MAIN
表示這個方法在主線程中執行(適合做異步加載,可以將子線程加載到數據直接設置到UI界面裏)
@Subscribe(threadMode = ThreadMode.MAIN)
public void MessageEventBus(EventBusMessage eventBusMessage){
//在TextView顯示接收的消息,從這個類裏拿屬性.
tv_title.setText(eventBusMessage.Message);
Log.d("eventBusThread","ThreadMode.MAIN "+Thread.currentThread().getName());
}
2. ThreadMode.POSTING
表示該方法和消息發送方在同一個線程.
@Subscribe(threadMode = ThreadMode.POSTING)
public void MessageEventBus1(EventBusMessage eventBusMessage){
Log.d("eventBusThread","ThreadMode.POSTING "+Thread.currentThread().getName());
}
3. ThreadMode.ASYNC
- 也表示在後臺執行(也就是子線程執行),可以異步併發處理
(適用於多個線程任務處理,內部有線程池管理,比如請求網絡時,用這個方法,他會自動創建線程去請求) - 無論發佈者是在子線程還是主線程,該方法都會創建一個子線程,在子線程執行.
@Subscribe(threadMode = ThreadMode.ASYNC)
public void MessageEventBus2(EventBusMessage eventBusMessage){
Log.d("eventBusThread","ThreadMode.ASYNC "+Thread.currentThread().getName());
}
4. ThreadMode.BACKGROUND
- 表示該方法在後臺運行(也就是子線程),不能夠併發處理
- 如果發佈者在子線程,那麼該方法就在子線程執行
- 如果發佈者在主線程,那麼該方法就會創建一個子線程,在子線程運行.
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void MessageEventBus3(EventBusMessage eventBusMessage){
Log.d("eventBusThread","ThreadMode.BACKGROUND "+Thread.currentThread().getName());
}
EventBus的黏性事件使用
一些帶有重要數據的事件發佈,例如,一個事件信號,一些初始化完成。或者如果你有傳感器位置數據和你想抓住最近的值。 這些重要信息不需要我們來緩存,使用sticky event就可以了,EventBus會緩存最近發送的sticky event事件,然後sticky event可以交付給用戶或顯式查詢。你不需要任何特殊的邏輯來考慮可用的數據。
如果一個sticky event在一段時間之前發送了
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
現在有一個activity啓動了,在註冊的期間,所有的sticky觀察者方法,將會立刻收到之前發送的sticky event.
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
// UI updates must run on MainThread
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {
textField.setText(event.message);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
正因爲上面所說的,所以有時需要手動檢查事件,還可能需要刪除事件,這樣他們不會被髮送了。這裏是removeStickyEvent方法
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
// "Consume" the sticky event
EventBus.getDefault().removeStickyEvent(stickyEvent);
// Now do something with it
}
我們也可以重寫上面的方法,如下:
MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
// Now do something with it
}