EventBus 3.X 的使用

這篇文章主要記錄一下EventBus的使用,詳情EventBus官方文檔

1. 概念

EventBus能夠簡化各組件間的通信,讓我們的代碼書寫變得簡單,能有效的分離事件發(fā)送方和接收方(也就是解耦的意思),能避免復(fù)雜和容易出錯(cuò)的依賴性和生命周期問題。

  • 事件(Event):又可稱為消息,本文中統(tǒng)一用事件表示。其實(shí)就是一個(gè)POJO對象
    事件分為一般事件和 Sticky 事件,相對于一般事件,Sticky 事件不同之處在于,當(dāng)事件發(fā)布后,再有訂閱者開始訂閱該類型事件,依然能收到該類型事件最近一個(gè) Sticky 事件。

  • 訂閱者(Subscriber):訂閱某種事件類型的對象。當(dāng)有發(fā)布者發(fā)布這類事件后,EventBus 會(huì)執(zhí)行訂閱者的 @Subscribe注解標(biāo)記的方法,叫做事件響應(yīng)。訂閱者通過 register 接口訂閱某個(gè)事件類型,unregister 接口退訂。訂閱者存在優(yōu)先級,優(yōu)先級高的訂閱者可以取消事件繼續(xù)向優(yōu)先級低的訂閱者分發(fā)(但是取消事件的線程必須和發(fā)布事件的線程一致),默認(rèn)所有訂閱者優(yōu)先級都為 0。

  • 發(fā)布者(Publisher):發(fā)布某事件的對象,通過 post 接口發(fā)布事件。

2. 簡單使用

2.1. 添加EventBus庫
api 'org.greenrobot:eventbus:3.1.1'
2.2. 新建一個(gè)POJO對象代表一個(gè)事件(Event)
public class MessageEvent {

    public final String message;

    public MessageEvent(String message) {
        this.message = message;
    }
}
2.3. 在生命周期里面注冊和取消注冊
@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}
 
@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}
2.4. 訂閱者處理事件
// 當(dāng) MessageEvent 事件被發(fā)布這個(gè)方法會(huì)被調(diào)用(在主線程中顯示一個(gè) Toast)
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
    Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}

2.5. 發(fā)布事件

發(fā)布事件的類和訂閱者的類不相同時(shí),兩個(gè)類不直接引用就可以進(jìn)行通信.

EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

3. 擴(kuò)展

3.1. ThreadMode (線程模式)

訂閱者響應(yīng)事件的方法是通過 @Subscribe 注解標(biāo)注的,其中有個(gè) ThreadMode 屬性可以進(jìn)行控制響應(yīng)事件方法的執(zhí)行線程,一共有 5 種線程模式可以進(jìn)行配置

  • ThreadMode: POSTING (默認(rèn))

訂閱者(Subscriber)發(fā)布者(Publisher) post 事件相同的線程中執(zhí)行響應(yīng)事件的方法,若 發(fā)布者(Publisher) post 的線程是主線程,則 訂閱者(Subscriber) 處理事件的線程也在主線程中執(zhí)行,若 發(fā)布者(Publisher) post 事件的線程是子線程,則 訂閱者(Subscriber) 處理消息事件的線程也是在子線程中執(zhí)行.

// Called in the same thread (default)
// ThreadMode is optional here
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessage(MessageEvent event) {
    log(event.message);
}
  • ThreadMode: MAIN

訂閱者(Subscriber) 在主線程中執(zhí)行響應(yīng)事件的方法,如果 發(fā)布者(Publisher) post 事件是主線程,則直接調(diào)用響應(yīng)事件的方法,如果 post 的是子線程,則加入到主線程的消息循環(huán)隊(duì)列中執(zhí)行響應(yīng)事件的方法,

// Called in Android UI's main thread
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
    textField.setText(event.message);
}
  • ThreadMode: MAIN_ORDERED

訂閱者(Subscriber) 在主線程中執(zhí)行響應(yīng)事件的方法 和 ThreadMode: MAIN 區(qū)別在于,不管 發(fā)布者(Publisher) post 事件是什么線程 ,MAIN_ORDERED會(huì)把事件加入到主線程的消息循環(huán)隊(duì)列中執(zhí)行,而不會(huì)直接調(diào)用處理消息的方法

// Called in Android UI's main thread
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMessage(MessageEvent event) {
    textField.setText(event.message);
}
  • ThreadMode: BACKGROUND

訂閱者(Subscriber) 在子線程中執(zhí)行響應(yīng)事件的方法.若 發(fā)布者(Publisher) post 事件為主線程,則在后臺(tái)子線程中執(zhí)行.所有的 ThreadMode: BACKGROUND 事件要轉(zhuǎn)化在子線程處理的都共用一個(gè)相同的后臺(tái)子線程 ,若 發(fā)布者(Publisher) post 事件的線程為子線程,則就直接在 post 事件的線程中處理.

// Called in the background thread
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event){
    saveToDisk(event.message);
}
  • ThreadMode: ASYNC

訂閱者(Subscriber) 在獨(dú)立的子線程中執(zhí)行響應(yīng)事件的方法,既不是 發(fā)布者(Publisher) post 事件的線程,不是主線程,也不是 ThreadMode: BACKGROUND 的后臺(tái)子線程 .發(fā)布者(Publisher) post 事件的線程不會(huì)等待訂閱者(Subscriber) 處理事件的線程響應(yīng).適用于處理事件時(shí)間較長的情況

// Called in a separate thread
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event){
    backend.send(event.message);
}
3.2. EventBus 配置
EventBus eventBus = EventBus.builder()
    .logSubscriberExceptions(false) // 默認(rèn)為 ture  是否記錄 調(diào)用訂閱者響應(yīng)事件的方法出現(xiàn)異常時(shí)的異常日志
    .logNoSubscriberMessages(false) // 默認(rèn)為 ture  是否記錄 發(fā)布者(Publisher) 發(fā)布事件時(shí)沒有訂閱者(Subscriber)  的日志 
    .sendNoSubscriberEvent(false) // 默認(rèn)為 ture 當(dāng)發(fā)布者(Publisher) 發(fā)布事件時(shí)沒有訂閱者(Subscriber) 是否將事件轉(zhuǎn)化為 post 一個(gè) NoSubscriberEvent事件
    .sendSubscriberExceptionEvent(false) // 默認(rèn)為 ture 調(diào)用訂閱者響應(yīng)事件的方法出現(xiàn)異常時(shí) 是否 post 一個(gè)SubscriberExceptionEvent 事件
    .throwSubscriberException(BuildConfig.DEBUG) // 默認(rèn)為 false 調(diào)用訂閱者響應(yīng)事件的方法出現(xiàn)異常時(shí)是否拋出 EventBusException
    .eventInheritance(false) // 默認(rèn)為 ture 若 發(fā)布者(Publisher) 發(fā)布的事件是訂閱者(Subscriber) 的訂閱事件的子類,是否將事件傳遞給訂閱者(Subscriber) 處理
    .ignoreGeneratedIndex(true) //默認(rèn)為 false 是否忽略 Index 
    .strictMethodVerification(true) // 默認(rèn)為 false ,是否嚴(yán)格認(rèn)證 @Subscribe 注解標(biāo)注的訂閱者響應(yīng)事件方法,如果 方法是0個(gè)或多于1個(gè)參數(shù),或者是 非 public, 抽象的,靜態(tài)的,會(huì)拋出 EventBusException
    .installDefaultEventBus();
3.3. Sticky 事件

Sticky 事件不同之處在于,當(dāng)事件發(fā)布后,再有訂閱者開始訂閱該類型事件,依然能收到該類型事件最近一個(gè) Sticky 事件。

  • 訂閱Sticky事件
// UI updates must run on MainThread
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {   
    textField.setText(event.message);
}
  • 發(fā)布Sticky事件
EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
  • 移除Sticky事件

Sticky事件 在事件發(fā)布之后依然會(huì)接收的到,所以不會(huì)丟失,若不需要時(shí)必須手動(dòng)移除

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
}

移除 Sticky事件 還有一個(gè)重載的方法

MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
    // Now do something with it
}
3.4. 優(yōu)先級和取消事件傳遞
  • 優(yōu)先級

默認(rèn)優(yōu)先級是 0,高優(yōu)先級的的訂閱者先接收到事件.只有相同在ThreadMode 下才能比較優(yōu)先級 不同的 ThreadMode下的訂閱者的優(yōu)先級別不起作用

@Subscribe(priority = 1);
public void onEvent(MessageEvent event) {
    ...
}
  • 取消事件傳遞

只有 和 發(fā)布者(Publisher) post 事件相同的線程的 訂閱者(Subscriber) 才能取消事件傳遞,不然的話會(huì)報(bào)異常

/ Called in the same thread (default)
@Subscribe
public void onEvent(MessageEvent event){
    // Process the event
    ...
    // Prevent delivery to other subscribers
    EventBus.getDefault().cancelEventDelivery(event) ;
}
3.5. Index(索引)

Index是 EventBus 3 上添加的新特性,默認(rèn)是用使用反射,而 Index 是編譯時(shí) 使用 annotationProcessor 生成輔助的 SubscriberInfoIndex 類 ,里面會(huì)記錄訂閱者信息,就不用反射掃描類中方法的,所以 Android上推薦使用 Index ,效率更高

  • 使用 annotationProcessor 生成 Index
android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ eventBusIndex : 'com.example.myapp.MyEventBusIndex' ]
            }
        }
    }
}

dependencies {
    implementation 'org.greenrobot:eventbus:3.1.1'
    annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
}
  • 使用 index

配置好 annotationProcessor 后使用 index 和之前的唯一區(qū)別是 EventBus.getDefault()之前必須使用 addIndex 方法進(jìn)行初始化

EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// Now the default instance uses the given index. Use it like this:
EventBus eventBus = EventBus.getDefault();
3.6. AsyncExecutor 輔助類

AsyncExecutor是一個(gè)輔助類會(huì)創(chuàng)建一個(gè)線程池,在 RunnableEx 里面執(zhí)行出現(xiàn)異常會(huì)被捕獲不用自己處理,并被轉(zhuǎn)化為一個(gè) ThrowableFailureEvent事件并 post 出去

AsyncExecutor.create().execute(
    new AsyncExecutor.RunnableEx() {
        @Override
        public void run() throws LoginException {
            // No need to catch any Exception (here: LoginException)
            remote.login();
            EventBus.getDefault().postSticky(new LoggedInEvent());
        }
    }
);

@Subscribe(threadMode = ThreadMode.MAIN)
public void handleLoginEvent(LoggedInEvent event) {
    // do something
}
 
@Subscribe(threadMode = ThreadMode.MAIN)
public void handleFailureEvent(ThrowableFailureEvent event) {
    // do something
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、簡介 EventBus是由greenrobot 組織貢獻(xiàn)的一個(gè)Android事件發(fā)布/訂閱輕量級框架。Even...
    Mr丶sorrow閱讀 15,399評論 0 13
  • 好久沒更新博客了,思來想去,時(shí)隔半年又重新了回來了 最近項(xiàng)目更新想用下greenrobot的eventbus,之前...
    Luke_單車閱讀 8,805評論 0 11
  • 什么是EventBus EventBus是Android下高效的發(fā)布/訂閱事件總線機(jī)制。作用是可以代替?zhèn)鹘y(tǒng)的Int...
    時(shí)光磨棱角閱讀 1,371評論 0 1
  • EVentBus的使用: 簡介下載地址使用步驟粘性事件例子 1.簡介 EventBus是一個(gè)Android端優(yōu)化的...
    努力生活的西魚閱讀 426評論 0 0
  • EventBus是一個(gè)Android平臺(tái)上的事件發(fā)送/訂閱框架,采用觀察者模式實(shí)現(xiàn),可以優(yōu)化組件間的信息傳遞過程。...
    華枯榮閱讀 5,073評論 2 3

友情鏈接更多精彩內(nèi)容