EventBus使用詳解

本文的EventBus,是指greenrobot的 EventBus, 主要以EventBus3.0 講解;

什么是EventBus?

EventBus事件總線, 用于簡(jiǎn)化Android程序內(nèi),各個(gè)組件,線程之間的事件傳遞; 訂閱發(fā)布模式,將事件的接收者和發(fā)布者解耦,一旦publisher發(fā)出消息,subscribe自己按需改變; 我個(gè)人喜歡把它拿來和BroadCast比較;

在什么場(chǎng)景下使用

  1. 復(fù)雜邏輯下的對(duì)象傳遞
  2. 函數(shù)的調(diào)用者與被調(diào)用者需要低耦合,或者框架設(shè)計(jì)之初,無法預(yù)料到的調(diào)用

eg. 上面的使用場(chǎng)景,在我們代碼中時(shí)長(zhǎng)出現(xiàn)的場(chǎng)景就是,監(jiān)聽器的傳遞,回調(diào)函數(shù)和各種Listener;
比如,在一個(gè)activity中,又2個(gè)fragment,而每個(gè)fragment中又各嵌套一個(gè)子fragment, 其中一個(gè)子fragment要監(jiān)聽另一個(gè)子fragment中的按鈕變化; 一般做法是將listener作為函數(shù)參數(shù)傳遞, 或者設(shè)置為靜態(tài)變量;
第二個(gè), 就和BoardCast相似

怎么使用

  1. 在gradle中添加依賴
dependencies {
       compile 'org.greenrobot:eventbus:3.0.0'
}
  1. 注冊(cè)和取消注冊(cè)
    在要接收消息的類中register unregister, 和廣播的注冊(cè)類似, 一般在activity的 onCreate 和 onDestory 方法中進(jìn)行
EventBus.getDefault().register( this );
EventBus.getDefault().unregister( this );
  1. 申明處理消息的函數(shù);
    在接收消息的函數(shù)上,加上@Subscribe, EventBus是按函數(shù)參數(shù)的類型確認(rèn)消息的接收者的, 此函數(shù)只能有且僅有一個(gè)參數(shù);
@Subscribe(threadMode = ThreadMode.MAIN, priority = 1, sticky = false)
public void onEvent( TestEvent  testEvent ){    
    Log.e( "zy", ">>>> receiverEvent");
}

只需要在函數(shù)上加上 @Subscribe 注解即可, 此注解還可以帶上額外的參數(shù)

  • threadMode , 用于指定此函數(shù)運(yùn)行的線程, 是一個(gè)Enum, 有4個(gè)常量, MAIN BACKGROUND ASYNC POSTING, 默認(rèn)為POSTING
    ThreadMode.MAIN 在主線程中運(yùn)行
    ThreadMode.POSTING 跟消息發(fā)送者在同一線程運(yùn)行
    ThreadMode.BACKGROUND 后臺(tái)線程, 如果發(fā)送消息的線程就是后臺(tái)線程,就直接執(zhí)行; 如果不是, 則會(huì)把消息放在隊(duì)列中,依次執(zhí)行
    ThreadMode.ASYNC 后臺(tái)線程, 消息會(huì)在單獨(dú)的線程中執(zhí)行,用了線程池,多個(gè)消息會(huì)同時(shí)執(zhí)行

  • priority 優(yōu)先級(jí), 值越小優(yōu)先級(jí)越低,當(dāng)有多個(gè)方法處理同一個(gè)消息時(shí),處理的順序,默認(rèn)為0

  • sticky 是否接收黏性消息, 和黏性廣播相同, 默認(rèn)為false

  1. 發(fā)送消息
    所謂的消息,就只是一個(gè)java對(duì)象, 發(fā)送消息就是把這個(gè)對(duì)象,傳遞給處理消息的函數(shù); EventBus消息和EventBus的對(duì)象實(shí)例有關(guān), 用一個(gè)EventBus對(duì)象發(fā)送的消息,必須是用同一個(gè)EventBus對(duì)象注冊(cè)的才能收到消息.
// 發(fā)送黏性消息
EventBus.getDefault().postSticky( new TestEvent() );
// 發(fā)送普通的消息
EventBus.getDefault().post( new TestEvent() );

發(fā)送的消息有2種,
sticky黏性消息, 當(dāng)消息發(fā)送出去之后,如果沒有消息接收者處理這個(gè)消息,此消息會(huì)暫時(shí)存儲(chǔ)在eventBus實(shí)例中, 當(dāng)后面注冊(cè)接受者時(shí),如果合適的處理者, 將會(huì)把消息給處理者去處理;我個(gè)人喜歡用這個(gè)來做數(shù)據(jù)的預(yù)加載;

  1. 提升性能, 增加編譯時(shí)注解處理
    由于android機(jī)器本身性能有限,一般不建議使用運(yùn)行時(shí)注解,EventBus的注解聲明為Runtime, 但它同時(shí)支持編譯時(shí)注解和運(yùn)行時(shí)注解, 當(dāng)沒配置編譯時(shí)注解處理器時(shí), 會(huì)自動(dòng)通過反射查找運(yùn)行時(shí)的注解;
    1. 添加注解處理器依賴
buildscript {
    ...
    dependencies {
          classpath 'com.android.tools.build:gradle:2.1.0'
          // 在最外層添加gradle的插件依賴
          classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
      }
  ...
}
// 項(xiàng)目中 增加注解處理器插件
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
       compile 'org.greenrobot:eventbus:3.0.0'
      // 添加注解處理器
      apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}
apt {
    arguments {
        // 注解處理器 最終生成的java文件位置
        eventBusIndex "com.zy.test.MyEventBusIndex"
    }
}
2. 初始化EventBus時(shí), 使用注解處理器生成的類文件
    ```java  
mEventBus = EventBus.builder().addIndex( new MyEventBusIndex() ).build();
     ```
 EventBus的消息和EventBus實(shí)例有關(guān)系, 自己配置的EventBus實(shí)例,一般需要用單例保存, 確保發(fā)送和接收消息的地方,使用的是同一個(gè)實(shí)例

關(guān)于其他的一些細(xì)節(jié)

- 消息處理者的繼承
EventBus的消息處理者,是可以繼承的, 父類中的消息處理器, 在子類中仍可使用; 這是一個(gè)比較好的功能, 比如通用的消息接收處理,我們?cè)贐aseActivity中聲明一次, 子類都可以使用了; 此功能可以關(guān)閉, 在構(gòu)建Eventbus實(shí)例時(shí), 調(diào)用 `EventBus.builder().eventInheritance( false )` ; 官方的說法是關(guān)閉后可以提供20%的性能;
  • 黏性消息
    非常實(shí)用的功能, 我一般用來做預(yù)加載數(shù)據(jù); 每種消息類型,最多存儲(chǔ)一個(gè)黏性消息, 和黏性廣播類似; 消息處理者. 聲明為sticky = true, 依然可以接收普通消息
  • 進(jìn)程間的通訊
    Eventbus的發(fā)送消息和消息處理是和Eventbus實(shí)例有關(guān)的, 是無法跨進(jìn)程傳遞消息的; 如果涉及到進(jìn)程間通訊, 還是要使用android系統(tǒng)的接口

對(duì)比

  1. Boardcast
    優(yōu)點(diǎn): 可以指定運(yùn)行線程, 消息處理可繼承, 代碼簡(jiǎn)單, 消息處理可繼承, 低延遲, 對(duì)消息數(shù)據(jù)無要求(不需要實(shí)現(xiàn)Parcelable或者Serializable接口)
    缺點(diǎn): 無法跨進(jìn)程
  2. LocalBroadcastManager
    這個(gè)除了廣播的低延遲外, Boardcast的缺點(diǎn)都有, 并且它還不能不能跨進(jìn)程, 沒有黏性廣播
  3. RxBus

源碼初探

EventBus的源碼不多, 這里只講一下大概, 具體細(xì)節(jié)大家自己去讀源碼
源碼版本( 66ead83 )

  1. EventBus.java
    此類對(duì)外提供所有的接口,register, unregister, post;
    提供一個(gè)默認(rèn)的單例對(duì)象, 通過getDefault()獲取;
    核心的變量如下
/** eventType和消息接收者存儲(chǔ)的map, key是event的class, value是接收者的信息, Subscription中包含的接收消息的對(duì)象, 處理消息的方法 */
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
/** 消息處理者和其所包含的能處理的event的Map, key為消息處理者的實(shí)例, value為其所能處理的event的類型 */
private final Map<Object, List<Class<?>>> typesBySubscriber;
/** sticky event 的存儲(chǔ)的Map, key為event的class, value是具體事件的對(duì)象, 每種類型的sticky event 最多存儲(chǔ)一個(gè) */
private final Map<Class<?>, Object> stickyEvents;
  1. SubscriberMethodFinder.java
    用于尋找消息處理者的方法, 里面有一個(gè)靜態(tài)變量 Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE 用于保存找到的消息處理這, 加快下一次查找過程

  2. HandlerPoster.java
    HandlerPoster 本質(zhì)是一個(gè)Handler, 使用主線程的Looper, 可以看一下初始化語句 mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); 發(fā)送到主線程的消息, 實(shí)質(zhì)都是用此發(fā)送一個(gè)Message, 然后在Handler#handleMessage中, 調(diào)用 Method#invoke(Object, Event);

  3. AsyncPoster.java BackgroundPoster.java
    名稱已經(jīng)很明顯, 處理后臺(tái)消息的2個(gè)類; 本質(zhì)都是Runnable, 都從消息隊(duì)列中獲取消息, 然后在線程池中執(zhí)行

  4. PendingPostQueue.java
    消息存儲(chǔ)的地方, 一個(gè)簡(jiǎn)單的鏈表結(jié)構(gòu)

  • 注冊(cè)流程
    register后, 會(huì)通過SubscriberMethodFinder#findSubscriberMethods方法, 查找注冊(cè)的類, 如果添加注解處理器, 會(huì)通過反射去查找; 查找后,將各個(gè)對(duì)應(yīng)關(guān)系保存在Eventbus實(shí)例的成員變量; 并且檢測(cè)是否有黏性消息, 有黏性消息,則立馬執(zhí)行

    post流程, 有ThreadLocal獲取所在線程信息, 然后在 Eventbus#subscriptionsByEventType獲取所有的消息處理者, 然后判斷處理的線程, 分發(fā)到各個(gè)Poster去處理

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

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

  • 前言:EventBus出來已經(jīng)有一段時(shí)間了,github上面也有很多開源項(xiàng)目中使用了EventBus。所以抽空學(xué)習(xí)...
    Kerry202閱讀 1,370評(píng)論 1 2
  • 前言:EventBus出來已經(jīng)有一段時(shí)間了,github上面也有很多開源項(xiàng)目中使用了EventBus。所以抽空學(xué)習(xí)...
    Lauren_Liuling閱讀 48,656評(píng)論 23 155
  • 目錄 1.概述 2.實(shí)戰(zhàn) 1.基本框架搭建 2.新建一個(gè)類FirstEvent 3.在要接收消息的頁面注冊(cè)Even...
    慕涵盛華閱讀 10,615評(píng)論 2 16
  • 前言 最近在公司做一個(gè)類似于手機(jī)工廠模式的一個(gè)項(xiàng)目,用來檢測(cè)其他各個(gè)App是否正常工作,所以要求是盡可能的輕量級(jí),...
    Luckily_Liu閱讀 1,252評(píng)論 2 8
  • 概述 EventBus是一個(gè)Android事件發(fā)布/訂閱框架,通過解耦發(fā)布者和訂閱者簡(jiǎn)化Android事件傳遞,這...
    劉滌生閱讀 79,106評(píng)論 6 57

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