Android事件總線框架之EventBus(3.0爲例)

實際項目開發過程中,經常遇到如下場景:不同的應用程序組件的控件間具有一定的相互關聯性,其中用戶對後者進行的某種操作會引起前者的相應改變。舉一個具體的場景:以新浪微博爲例,在新浪微博首頁好友動態列表頁和好友動態詳情頁(微博正文),對於每個詳情頁而言,佈局基本一致,在詳情頁點擊了個贊,讚的數量增加,同時讚的圖標發生了變化,此時返回到列表頁,此新浪微博首頁上的贊圖標以及數量與剛剛詳情頁的需要保持一致。再舉一個例子,對於多個底部導航tab下的資訊類閱讀app,在諮詢詳情頁點擊了收藏,然後收藏成功,此時回到底部tab中的個人中心,假如個人中心中有我的收藏,同時後面顯示的是收藏數量,此時此收藏數量需要同於於剛剛用戶所進行的收藏/取消收藏而即時更改數字。顯而易見,類似場景需求非常常見。

有時候,當此類需求相對簡單時,通過接口以實現回調等方式可以完成,但是當不同組件/控件之間的關係紛繁複雜時,基於接口的方案不僅使得代碼非常繁瑣,同時是的程序邏輯很混亂,基於此,Android事件總線框架(AndroidEventBus 、EventBus、Otto) ,爲此類需求的實現提供了非常方便的方案。

這裏我以EventBus框架爲例,爲大家實現該功能。


什麼是EventBus?

EventBus是Android下高效的發佈/訂閱事件總線機制。作用是可以代替傳統的Intent,Handler,Broadcast或接口函數在Fragment,Activity,Service,線程之間傳遞數據,執行方法。特點是代碼簡潔,是一種發佈訂閱設計模式(Publish/Subsribe),或稱作觀察者設計模式。事件傳遞既可用於 Android 四大組件間通訊,也可以用戶異步線程和主線程間通訊等等。傳統的事件傳遞方式包括:Handler、BroadCastReceiver、Interface 回調,相比之下 EventBus 的優點是代碼簡潔,使用簡單,並將事件發佈和訂閱充分解耦。

EventBus框架 基本結構


EventBus 負責存儲訂閱者、事件相關信息,訂閱者和發佈者都只和 EventBus 關聯。

EventBus作爲一個消息總線,有三個主要的元素:

  • Event:事件。可以是任意類型的對象
  • Subscriber:事件訂閱者,接收特定的事件。在EventBus中,使用約定來指定事件訂閱者以簡化使用。即所有事件訂閱都都是以onEvent開頭的函數,具體來說,函數的名字是onEvent,onEventMainThread,onEventBackgroundThread,onEventAsync這四個,這個和 
    ThreadMode(下面講)有關。
  • Publisher:事件發佈者,用於通知 Subscriber 有事件發生。可以在任意線程任意位置發送事件,直接調用eventBus.post(Object) 方法,可以自己實例化 EventBus 
    對象,但一般使用默認的單例就好了:EventBus.getDefault(), 根據post函數參數的類型,會自動調用訂閱相應類型事件的函數。


事件響應流程圖


訂閱者首先調用 EventBus 的 register 接口訂閱某種類型的事件,當發佈者通過 post 接口發佈該類型的事件時,EventBus 執行調用者的事件響應函數。


EventBus使用詳解

EventBus使用步驟

1.引入EventBus:
引入eventbus:3.0.0

  compile 'org.greenrobot:eventbus:3.0.0'
2.構造發送消息類

註冊號事件訂閱者之後,第二步就是構造發送消息類,這個類就是我們要發送的對象,所以這個類怎麼寫都行,只要你把要傳遞的東西能夠存進這個對象中又能夠從這個對象中拿出來就好。OK,我寫了一個簡單的消息類,如下:

public class MainMessage {
    private String msg;

    public MainMessage(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }
}

3.註冊事件訂閱者
使用EventBus我們首先要註冊事件訂閱者,這個事件訂閱者就是說我們訂閱的事件一會要在哪裏進行處理,事件訂閱者的註冊和廣播註冊非常相似,有註冊,也有解除註冊,一般情況下,我們在Activity的onCreate()方法中進行註冊,在Activity的onDestory()方法中解除註冊。OK,代碼如下:

註冊:
EventBus.getDefault().register(this);
解除註冊:
EventBus.getDefault().unregister(this);
所以完整的代碼應該是這個樣子:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

4.發送事件:即發送消息
EventBus.getDefault().post(messageEvent);

5.處理消息
在3.0之前,EventBus還沒有使用註解方式。消息處理的方法也只能限定於onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,分別代表四種線程模型。而在3.0之後,消息處理的方法可以隨便取名,但是需要添加一個註解@Subscribe,並且要指定線程模型(beta1默認爲PostThread,正式版默認爲POSTING),四種線程模型,下面會講到。 
注意,事件處理函數的訪問權限必須爲public,否則會報異常。

以3.0版爲例
  @Subscribe(threadMode = ThreadMode.POSTING) //3.0.0
    public void onMessageEventPost(UserEvent event) {
    //默認方式, 在發送線程執行
    }

 @Subscribe(threadMode = ThreadMode.MAIN) 
    public void onMessageEventMain(UserEvent event) {
    //在ui線程執行
    }

   @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onMessageEventBackground(UserEvent event) {
     //在後臺線程執行
    }

 @Subscribe(threadMode = ThreadMode.ASYNC) 
    public void onMessageEventAsync(UserEvent event) {
    //強制在後臺執行
    }

注意:ThreadMode.BackgroundThread和ThreadMode.Async的不同之處是前者發送方在主線程而接收方就會在後臺線程處理消息,但如果發送方在一個子線程,那麼接收方和發送方在同一個線程處理消息,後者則強制接收方在後臺線程處理消息,不管發送方在哪個線程,但消息的處理都是異步的,如果後臺進程被阻塞,那麼就會開例外一個後臺線程,否則都在一個後臺線程中處理消息。


6.代碼混淆
 -keepclassmembers class ** {
    public void onEvent*(**);
    void onEvent*(**);
 }

注意:

@Subscribe 下的方法必須爲public
postSticky()發送的粘性消息訂閱時必須@Subscribe(sticky = true)否則接收不到
發送的event事件是object類
@Subscribe(priority = 1) 使用時優先級默認爲0,然後只有統一模式下設置優先級纔有效果,自己看着合理使用


EventBus demo下載




參考資料:








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章