EventBus使用詳解

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

什么是EventBus?

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

在什么場景下使用

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

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

怎么使用

  1. 在gradle中添加依賴
dependencies {
       compile 'org.greenrobot:eventbus:3.0.0'
}
  1. 注冊和取消注冊
    在要接收消息的類中register unregister, 和廣播的注冊類似, 一般在activity的 onCreate 和 onDestory 方法中進(jìn)行
EventBus.getDefault().register( this );
EventBus.getDefault().unregister( this );
  1. 申明處理消息的函數(shù);
    在接收消息的函數(shù)上,加上@Subscribe, EventBus是按函數(shù)參數(shù)的類型確認(rèn)消息的接收者的, 此函數(shù)只能有且僅有一個參數(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)行的線程, 是一個Enum, 有4個常量, MAIN BACKGROUND ASYNC POSTING, 默認(rèn)為POSTING
    ThreadMode.MAIN 在主線程中運(yùn)行
    ThreadMode.POSTING 跟消息發(fā)送者在同一線程運(yùn)行
    ThreadMode.BACKGROUND 后臺線程, 如果發(fā)送消息的線程就是后臺線程,就直接執(zhí)行; 如果不是, 則會把消息放在隊(duì)列中,依次執(zhí)行
    ThreadMode.ASYNC 后臺線程, 消息會在單獨(dú)的線程中執(zhí)行,用了線程池,多個消息會同時(shí)執(zhí)行

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

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

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

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

  1. 提升性能, 增加編譯時(shí)注解處理
    由于android機(jī)器本身性能有限,一般不建議使用運(yùn)行時(shí)注解,EventBus的注解聲明為Runtime, 但它同時(shí)支持編譯時(shí)注解和運(yùn)行時(shí)注解, 當(dāng)沒配置編譯時(shí)注解處理器時(shí), 會自動通過反射查找運(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ā)送和接收消息的地方,使用的是同一個實(shí)例

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

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

對比

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

源碼初探

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

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

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

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

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

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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