Android EventBus 的使用

2559b11d3220e9fc9ee87f8248419e74b7eb3ce1.jpg

1、EventBus 簡介

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

1.1 三個角色

  1. Event:事件颠悬,它可以是任意類型,EventBus會根據(jù)事件類型進(jìn)行全局的通知定血。
  2. Subscriber:事件訂閱者赔癌,在EventBus 3.0之前我們必須定義以onEvent開頭的那幾個方法,分別是onEvent澜沟、onEventMainThread届榄、onEventBackgroundThreadonEventAsync,而在3.0之后事件處理的方法名可以隨意取倔喂,不過需要加上注解@subscribe铝条,并且指定線程模型,默認(rèn)是POSTING席噩。
  3. Publisher:事件的發(fā)布者班缰,可以在任意線程里發(fā)布事件。一般情況下悼枢,使用EventBus.getDefault()就可以得到一個EventBus對象埠忘,然后再調(diào)用post(Object)方法即可。

1.2 四種線程模型

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

  1. POSTING:默認(rèn)莹妒,表示事件處理函數(shù)的線程跟發(fā)布事件的線程在同一個線程。
  2. MAIN:表示事件處理函數(shù)的線程在主線程(UI)線程绰上,因此在這里不能進(jìn)行耗時操作旨怠。
  3. BACKGROUND:表示事件處理函數(shù)的線程在后臺線程,因此不能進(jìn)行UI操作蜈块。如果發(fā)布事件的線程是主線程(UI線程)鉴腻,那么事件處理函數(shù)將會開啟一個后臺線程,如果果發(fā)布事件的線程是在后臺線程百揭,那么事件處理函數(shù)就使用該線程爽哎。
  4. ASYNC:表示無論事件發(fā)布的線程是哪一個,事件處理函數(shù)始終會新建一個子線程運行器一,同樣不能進(jìn)行UI操作课锌。

2、EventBus 使用

2.1 引入依賴

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

implementation 'org.greenrobot:eventbus:3.1.1'

2.2 定義事件

然后祈秕,我們定義一個事件的封裝對象渺贤。在程序內(nèi)部就使用該對象作為通信的信息:

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

這里我們當(dāng)按下按鈕的時候向EventBus注冊監(jiān)聽踢步,然后按下另一個按鈕的時候跳轉(zhuǎn)到拎一個Activity癣亚,并在另一個Activity發(fā)布我們輸入的事件。在上面的Activity中获印,我們會添加一個監(jiān)聽的方法述雾,即onGetMessage,這里我們需要為其加入注解Subscribe并指定線程模型為主線程MAIN兼丰。最后玻孟,就是在Activity的onDestroy方法中取消注冊該Activity。

下面是另一個Activity的定義鳍征,在這個Activity中黍翎,我們當(dāng)按下按鈕的時候從EditText中取出內(nèi)容并進(jìn)行發(fā)布,然后我們退出到之前的Activity艳丛,以測試是否正確監(jiān)聽到發(fā)布的內(nèi)容匣掸。

@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ù)測試的結(jié)果趟紊,我們的確成功地接收到了發(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ā)布黏性事件。即調(diào)用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ù)測試結(jié)果帖烘,當(dāng)按下注冊按鈕的時候,會立即觸發(fā)上面的訂閱方法從而獲取到了黏性事件爽航。

2.5 優(yōu)先級

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

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

這里有幾個地方需要注意

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

所以娶视,根據(jù)以上的內(nèi)容,我們需要對代碼做如下的調(diào)整:

// 用來判斷是否需要停止事件的繼續(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寒锚。

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

總結(jié)

上面的內(nèi)容是EventBus的基本使用方法膏斤,相關(guān)的源碼參考:Github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市邪驮,隨后出現(xiàn)的幾起案子莫辨,更是在濱河造成了極大的恐慌,老刑警劉巖毅访,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沮榜,死亡現(xiàn)場離奇詭異,居然都是意外死亡喻粹,警方通過查閱死者的電腦和手機蟆融,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來守呜,“玉大人型酥,你說我怎么就攤上這事〕诜梗” “怎么了冕末?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長侣颂。 經(jīng)常有香客問我档桃,道長,這世上最難降的妖魔是什么憔晒? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任藻肄,我火速辦了婚禮蔑舞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嘹屯。我一直安慰自己攻询,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布州弟。 她就那樣靜靜地躺著钧栖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪婆翔。 梳的紋絲不亂的頭發(fā)上拯杠,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音啃奴,去河邊找鬼潭陪。 笑死,一個胖子當(dāng)著我的面吹牛最蕾,可吹牛的內(nèi)容都是我干的依溯。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼瘟则,長吁一口氣:“原來是場噩夢啊……” “哼黎炉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起壹粟,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤拜隧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后趁仙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洪添,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年雀费,在試婚紗的時候發(fā)現(xiàn)自己被綠了干奢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡盏袄,死狀恐怖忿峻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情辕羽,我是刑警寧澤逛尚,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站刁愿,受9級特大地震影響绰寞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一滤钱、第九天 我趴在偏房一處隱蔽的房頂上張望觉壶。 院中可真熱鬧,春花似錦件缸、人聲如沸铜靶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽争剿。三九已至,卻和暖如春痊末,著一層夾襖步出監(jiān)牢的瞬間秒梅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工舌胶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疮丛。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓幔嫂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親誊薄。 傳聞我的和親對象是個殘疾皇子履恩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 2017.04.27-28 瑞安新紀(jì)元實驗學(xué)校 一、基于核心素養(yǎng)的考試命題(華師大 楊向東) 理論的高度呢蔫。 二切心、基...
    秋十一張閱讀 663評論 0 0
  • 《創(chuàng)造性采訪》第三章-策劃采訪四原則: 1. 再次解釋目的 2. 策劃如何打招呼 3. 速記需要用提問來涉及的話題...
    曼思閱讀 198評論 0 0
  • 兒子學(xué)完奧數(shù),時有余暇片吊,又天氣晴暖绽昏,于是一家子去看油菜花。 賞油菜花俏脊,于最近幾年很是熱門全谤,民間追捧,政...
    半表閱讀 449評論 0 2
  • 選擇器 后代選擇器:選擇所有合乎規(guī)則的后代元素爷贫∪先唬空格連接。 相鄰后代選擇器:僅僅選擇合乎規(guī)則的兒子元素漫萄,孫子卷员、重孫...
    時間小魚閱讀 270評論 0 0