Android框架式編程之EventBus

1、EventBus 簡介

EventBus是一種用於Android的事件發佈-訂閱總線,由GreenRobot開發,Gihub地址是:EventBusgit

它簡化了應用程序內各個組件之間進行通訊的複雜度,尤爲是碎片之間進行通訊的問題,能夠避免因爲使用廣播通訊而帶來的諸多不便。github

1. EventBus的三個角色

  • Event:事件,它能夠是任意類型,EventBus會根據事件類型進行全局的通知。ide

  • Subscriber:事件訂閱者,在EventBus 3.0以前咱們必須定義以onEvent開頭的那幾個方法,分別是onEventonEventMainThreadonEventBackgroundThreadonEventAsync,而在3.0以後事件處理的方法名能夠隨意取,不過須要加上註解@subscribe,而且指定線程模型,默認是POSTING函數

  • Publisher:事件的發佈者,能夠在任意線程裏發佈事件。通常狀況下,使用EventBus.getDefault()就能夠獲得一個EventBus對象,而後再調用post(Object)方法便可。post

2. 四種線程模型

EventBus3.0有四種線程模型,分別是:測試

  • POSTING:默認,表示事件處理函數的線程跟發佈事件的線程在同一個線程。
  • MAIN:表示事件處理函數的線程在主線程(UI)線程,所以在這裏不能進行耗時操做。
  • BACKGROUND:表示事件處理函數的線程在後臺線程,所以不能進行UI操做。若是發佈事件的線程是主線程(UI線程),那麼事件處理函數將會開啓一個後臺線程,若是果發佈事件的線程是在後臺線程,那麼事件處理函數就使用該線程。
  • ASYNC:表示不管事件發佈的線程是哪個,事件處理函數始終會新建一個子線程運行,一樣不能進行UI操做。

2、EventBus 使用

1. 引入依賴

在使用以前先要引入以下依賴:ui

implementation 'org.greenrobot:eventbus:3.1.1'

2. 定義事件

定義一個事件的封裝對象。在程序內部就使用該對象做爲通訊的信息:this

public class MessageWrap {

    public final String message;

    public static MessageWrap getInstance(String message) {
        return new MessageWrap(message);
    }

    private MessageWrap(String message) {
        this.message = message;
    }
}

在定義事件對象的時候,而咱們能夠對字段進行拓展,方便後期的使用和維護。spa

3. 發佈事件

而後,咱們定義一個Activity:線程

@Route(path = BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY1)
public class EventBusActivity1 extends CommonActivity<ActivityEventBus1Binding> {

    @Override
    protected void doCreateView(Bundle savedInstanceState) {
        // 爲按鈕添加添加單擊事件
        getBinding().btnReg.setOnClickListener(v -> EventBus.getDefault().register(this));
        getBinding().btnNav2.setOnClickListener( v ->
                ARouter.getInstance()
                        .build(BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY2)
                        .navigation());
    }

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

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onGetMessage(MessageWrap message) {
        getBinding().tvMessage.setText(message.message);
    }
}

這裏咱們當按下按鈕的時候向EventBus註冊監聽,而後按下另外一個按鈕的時候跳轉到拎一個Activity,並在另外一個Activity發佈咱們輸入的事件。在上面的Activity中,咱們會添加一個監聽的方法,即onGetMessage,這裏咱們須要爲其加入註解Subscribe並指定線程模型爲主線程MAIN。最後,就是在Activity的onDestroy方法中取消註冊該Activity。

下面是另外一個Activity的定義,在這個Activity中,咱們當按下按鈕的時候從EditText中取出內容並進行發佈,而後咱們退出到以前的Activity,以測試是否正確監聽到發佈的內容。

@Route(path = BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY2)
public class EventBusActivity2 extends CommonActivity<ActivityEventBus2Binding> {

    @Override
    protected void doCreateView(Bundle savedInstanceState) {
        getBinding().btnPublish.setOnClickListener(v -> publishContent());
    }

    private void publishContent() {
        String msg = getBinding().etMessage.getText().toString();
        EventBus.getDefault().post(MessageWrap.getInstance(msg));
        ToastUtils.makeToast("Published : " + msg);
    }
}

根據測試的結果,咱們的確成功地接收到了發送的信息。

4. 黏性事件

所謂的黏性事件,就是指發送了該事件以後再訂閱者依然可以接收到的事件。使用黏性事件的時候有兩個地方須要作些修改。一個是訂閱事件的地方,這裏咱們在先打開的Activity中註冊監聽黏性事件:

@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onGetStickyEvent(MessageWrap message) {
    String txt = "Sticky event: " + message.message;
    getBinding().tvStickyMessage.setText(txt);
}

另外一個是發佈事件的地方,這裏咱們在新的開的Activity中發佈黏性事件。即調用EventBus的postSticky方法來發布事件:

private void publishStickyontent() {
    String msg = getBinding().etMessage.getText().toString();
    EventBus.getDefault().postSticky(MessageWrap.getInstance(msg));
    ToastUtils.makeToast("Published : " + msg);
}

按照上面的模式,咱們先在第一個Activity中打開第二個Activity,而後在第二個Activity中發佈黏性事件,並回到第一個Activity註冊EventBus。根據測試結果,當按下注冊按鈕的時候,會當即觸發上面的訂閱方法從而獲取到了黏性事件。

5. 優先級

Subscribe註解中總共有3個參數,上面咱們用到了其中的兩個,這裏咱們使用如下第三個參數,即priority。它用來指定訂閱方法的優先級,是一個整數類型的值,默認是0,值越大表示優先級越大。在某個事件被髮布出來的時候,優先級較高的訂閱方法會首先接受到事件。

爲了對優先級進行測試,這裏咱們須要對上面的代碼進行一些修改。這裏,咱們使用一個布爾類型的變量來判斷是否應該取消事件的分發。咱們在一個較高優先級的方法中經過該布爾值進行判斷,若是未true就中止該事件的繼續分發,從而經過低優先級的訂閱方法沒法獲取到事件來證實優先級較高的訂閱方法率先獲取到了事件。

這裏有幾個地方須要注意

1. 只有當兩個訂閱方法使用相同的ThreadMode參數的時候,它們的優先級纔會與priority指定的值一致;

2. 只有當某個訂閱方法的ThreadMode參數爲POSTING的時候,它才能中止該事件的繼續分發。

因此,根據以上的內容,咱們須要對代碼作以下的調整:

// 用來判斷是否須要中止事件的繼續分發
private boolean stopDelivery = false;

@Override
protected void doCreateView(Bundle savedInstanceState) {
    // ...

    getBinding().btnStop.setOnClickListener(v -> stopDelivery = true);
}

@Subscribe(threadMode = ThreadMode.POSTING, priority = 0)
public void onGetMessage(MessageWrap message) {
    getBinding().tvMessage.setText(message.message);
}

// 訂閱方法,須要與上面的方法的threadMode一致,而且優先級略高
@Subscribe(threadMode = ThreadMode.POSTING, sticky = true, priority = 1)
public void onGetStickyEvent(MessageWrap message) {
    String txt = "Sticky event: " + message.message;
    getBinding().tvStickyMessage.setText(txt);
    if (stopDelivery) {
        // 終止事件的繼續分發
        EventBus.getDefault().cancelEventDelivery(message);
    }
}

即咱們在以前的代碼之上增長了一個按鈕,用來將stopDelivery的值置爲true。該字段隨後將會被用來判斷是否要終止事件的繼續分發,由於咱們須要在代碼中中止事件的繼續分發,因此,咱們須要將上面的兩個訂閱方法的threadMode的值都置爲ThreadMode.POSTING

按照,上面的測試方式,首先咱們在當前的Activity註冊監聽,而後跳轉到另外一個Activity,發佈事件並返回。第一次的時候,這裏的兩個訂閱方法都會被觸發。而後,咱們按下中止分發的按鈕,並再次執行上面的邏輯,此時只有優先級較高的方法獲取到了事件並將該事件終止。

 

參考資料:https://www.jianshu.com/p/e7d5c7bda783

相關文章
相關標籤/搜索