Android EventBus 的使用

1、EventBus 簡介

EventBus是一種用于Android的事件發(fā)布-訂閱總線,由GreenRobot開發(fā),Gihub地址是:EventBus。它簡化了應用程序內各個組件之間進行通信的復雜度,尤其是碎片之間進行通信的問題,可以避免由于使用廣播通信而帶來的諸多不便。

1.1 三個角色

  1. Event:事件,它可以是任意類型,EventBus會根據(jù)事件類型進行全局的通知。
  2. Subscriber:事件訂閱者,在EventBus 3.0之前我們必須定義以onEvent開頭的那幾個方法,分別是onEvent、onEventMainThread、onEventBackgroundThreadonEventAsync,而在3.0之后事件處理的方法名可以隨意取,不過需要加上注解@subscribe,并且指定線程模型,默認是POSTING。
  3. Publisher:事件的發(fā)布者,可以在任意線程里發(fā)布事件。一般情況下,使用EventBus.getDefault()就可以得到一個EventBus對象,然后再調用post(Object)方法即可。

1.2 四種線程模型

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

  1. POSTING:默認,表示事件處理函數(shù)的線程跟發(fā)布事件的線程在同一個線程。
  2. MAIN:表示事件處理函數(shù)的線程在主線程(UI)線程,因此在這里不能進行耗時操作。
  3. BACKGROUND:表示事件處理函數(shù)的線程在后臺線程,因此不能進行UI操作。如果發(fā)布事件的線程是主線程(UI線程),那么事件處理函數(shù)將會開啟一個后臺線程,如果果發(fā)布事件的線程是在后臺線程,那么事件處理函數(shù)就使用該線程。
  4. ASYNC:表示無論事件發(fā)布的線程是哪一個,事件處理函數(shù)始終會新建一個子線程運行,同樣不能進行UI操作。

2、EventBus 使用

2.1 引入依賴

在使用之前先要引入如下依賴:

implementation 'org.greenrobot:eventbus:3.1.1'

2.2 定義事件

然后,我們定義一個事件的封裝對象。在程序內部就使用該對象作為通信的信息:

public class MessageWrap {

    public final String message;

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

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

2.3 發(fā)布事件

然后,我們定義一個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注冊監(jiān)聽,然后按下另一個按鈕的時候跳轉到拎一個Activity,并在另一個Activity發(fā)布我們輸入的事件。在上面的Activity中,我們會添加一個監(jiān)聽的方法,即onGetMessage,這里我們需要為其加入注解Subscribe并指定線程模型為主線程MAIN。最后,就是在Activity的onDestroy方法中取消注冊該Activity。

下面是另一個Activity的定義,在這個Activity中,我們當按下按鈕的時候從EditText中取出內容并進行發(fā)布,然后我們退出到之前的Activity,以測試是否正確監(jiān)聽到發(fā)布的內容。

@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);
    }
}

根據(jù)測試的結果,我們的確成功地接收到了發(fā)送的信息。

2.4 黏性事件

所謂的黏性事件,就是指發(fā)送了該事件之后再訂閱者依然能夠接收到的事件。使用黏性事件的時候有兩個地方需要做些修改。一個是訂閱事件的地方,這里我們在先打開的Activity中注冊監(jiān)聽黏性事件:

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

另一個是發(fā)布事件的地方,這里我們在新的開的Activity中發(fā)布黏性事件。即調用EventBus的postSticky方法來發(fā)布事件:

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

按照上面的模式,我們先在第一個Activity中打開第二個Activity,然后在第二個Activity中發(fā)布黏性事件,并回到第一個Activity注冊EventBus。根據(jù)測試結果,當按下注冊按鈕的時候,會立即觸發(fā)上面的訂閱方法從而獲取到了黏性事件。

2.5 優(yōu)先級

Subscribe注解中總共有3個參數(shù),上面我們用到了其中的兩個,這里我們使用以下第三個參數(shù),即priority。它用來指定訂閱方法的優(yōu)先級,是一個整數(shù)類型的值,默認是0,值越大表示優(yōu)先級越大。在某個事件被發(fā)布出來的時候,優(yōu)先級較高的訂閱方法會首先接受到事件。

為了對優(yōu)先級進行測試,這里我們需要對上面的代碼進行一些修改。這里,我們使用一個布爾類型的變量來判斷是否應該取消事件的分發(fā)。我們在一個較高優(yōu)先級的方法中通過該布爾值進行判斷,如果未true就停止該事件的繼續(xù)分發(fā),從而通過低優(yōu)先級的訂閱方法無法獲取到事件來證明優(yōu)先級較高的訂閱方法率先獲取到了事件。

這里有幾個地方需要注意

  1. 只有當兩個訂閱方法使用相同的ThreadMode參數(shù)的時候,它們的優(yōu)先級才會與priority指定的值一致;
  2. 只有當某個訂閱方法的ThreadMode參數(shù)為POSTING的時候,它才能停止該事件的繼續(xù)分發(fā)。

所以,根據(jù)以上的內容,我們需要對代碼做如下的調整:

// 用來判斷是否需要停止事件的繼續(xù)分發(fā)
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一致,并且優(yōu)先級略高
@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) {
        // 終止事件的繼續(xù)分發(fā)
        EventBus.getDefault().cancelEventDelivery(message);
    }
}

即我們在之前的代碼之上增加了一個按鈕,用來將stopDelivery的值置為true。該字段隨后將會被用來判斷是否要終止事件的繼續(xù)分發(fā),因為我們需要在代碼中停止事件的繼續(xù)分發(fā),所以,我們需要將上面的兩個訂閱方法的threadMode的值都置為ThreadMode.POSTING

按照,上面的測試方式,首先我們在當前的Activity注冊監(jiān)聽,然后跳轉到另一個Activity,發(fā)布事件并返回。第一次的時候,這里的兩個訂閱方法都會被觸發(fā)。然后,我們按下停止分發(fā)的按鈕,并再次執(zhí)行上面的邏輯,此時只有優(yōu)先級較高的方法獲取到了事件并將該事件終止。

總結

上面的內容是EventBus的基本使用方法,相關的源碼參考:Github

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 黑夜,給我無盡的想象, 黑夜,也給我無盡的苦痛。 今夜,我又無法安睡, 久違的老毛病又出來作怪。 我想點燃一只香煙...
    流氓痞子小騷年閱讀 230評論 0 0
  • 生活小事 和往常一樣,下班接孩子放學,走在路上,孩子突然提出要去買做手工的材料,欣然前往。 在等電梯去店里的...
    白小白2019閱讀 209評論 0 1
  • 一生秋閱讀 282評論 0 0
  • 最美好的人生,不看你人前有多嗨,而要看人后的你是滿足還是空白。
    艾艾落語閱讀 209評論 0 0
  • 人生都會有彎路要走。其實只要決心,真的隨時可以重新開始。現(xiàn)在迷惘什么呢?既然喜歡了,決定了,就走下去好了,錯了,就...
    結構學AI閱讀 163評論 0 0

友情鏈接更多精彩內容