EventBus源碼分析

EventBus-Publish-Subscribe.png

簡(jiǎn)述

EventBus是一款針對(duì)Android優(yōu)化的發(fā)布/訂閱事件總線。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,線程之間傳遞消息。優(yōu)點(diǎn)是開銷小,代碼更優(yōu)雅,以及將發(fā)送者和接收者解耦。

基本使用

1.新建一個(gè)類,AnyEventType。可以是網(wǎng)絡(luò)請(qǐng)求返回的字符串,也可以是某個(gè)開關(guān)狀態(tài),也可以是空。

public class AnyEventType {  
 public AnyEventType(){}  
}  

2.注冊(cè)訂閱者

EventBus.getDefault().register(this);

3.發(fā)送事件

EventBus.getDefault().post(new AnyEventType event);

4.編寫響應(yīng)事件訂閱方法

@Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true, priority = 100)
public void hello(String str) {

}  

這里說明一下3.0之后可以通過@Subscribe注解,來確定運(yùn)行的線程threadMode,是否接受粘性事件sticky以及事件優(yōu)先級(jí)priority,而且方法名不在需要onEvent開頭,所以又簡(jiǎn)潔靈活了不少.

5.解除注冊(cè)

EventBus.getDefault().unregister(this);

源碼解析

1.新建EventBus
  • 默認(rèn)可通過靜態(tài)函數(shù) getDefault 獲取單例

    public static EventBus getDefault() {
      if (defaultInstance == null) {
        synchronized (EventBus.class) {
      if (defaultInstance == null) {
        defaultInstance = new EventBus();
      }}}
    return defaultInstance;
    }
    
  • EventBusBuilder 新建一個(gè) EventBus

    public static EventBusBuilder builder() {
    return new EventBusBuilder();
    }
    
  • 構(gòu)造函數(shù)新建一個(gè)EventBus

    public EventBus() {
      this(DEFAULT_BUILDER);
    }
    
2.register

register 函數(shù)中會(huì)先根據(jù)訂閱者類名去subscriberMethodFinder
中查找當(dāng)前訂閱者所有事件響應(yīng)函數(shù),然后循環(huán)每一個(gè)事件響應(yīng)函數(shù),依次執(zhí)行subscribe 函數(shù)

public void register(Object subscriber) { 
subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); 
synchronized (this) { 
  for (SubscriberMethod subscriberMethod : subscriberMethods) { 
    subscribe(subscriber, subscriberMethod); 
    } 
  } 
}
register.png
3.subscribe

源碼太長就不全部貼出來了

1.首先通過subscriptionsByEventType得到該事件類型所有訂閱者信息隊(duì)列,根據(jù)優(yōu)先級(jí)將當(dāng)前訂閱者信息插入到訂閱者隊(duì)列subscriptionsByEventType中;如果添加過就拋出異常。

CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
    subscriptions = new CopyOnWriteArrayList<>();
    subscriptionsByEventType.put(eventType, subscriptions);
  } else {
  if (subscriptions.contains(newSubscription)) {
      throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "+ eventType);
    }
  }

2.在typesBySubscriber中得到當(dāng)前訂閱者訂閱的所有事件隊(duì)列,將此事件保存到隊(duì)列typesBySubscriber中,用于后續(xù)取消訂閱;

List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); 
if (subscribedEvents == null) { 
    subscribedEvents = new ArrayList<>();         
    typesBySubscriber.put(subscriber, subscribedEvents); 
  }

3.檢查這個(gè)事件是否是 Sticky 事件,如果是則立即分發(fā)sticky事件

if (subscriberMethod.sticky) { 
//eventInheritance 表示是否分發(fā)訂閱了響應(yīng)事件類父類事件的方法 
    if (eventInheritance) { 
       Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet(); 
       for (Map.Entry<Class<?>, Object> entry : entries) { 
          Class<?> candidateEventType = entry.getKey(); 
          if (eventType.isAssignableFrom(candidateEventType)) { 
            Object stickyEvent = entry.getValue(); 
            checkPostStickyEventToSubscription(newSubscription, stickyEvent); 
           } 
        } 
      } else { 
        Object stickyEvent = stickyEvents.get(eventType); 
        checkPostStickyEventToSubscription(newSubscription, stickyEvent); 
      } 
}
4.post

首先得到當(dāng)前線程的 post 信息PostingThreadState,其中包含事件隊(duì)列,將當(dāng)前事件添加到其事件隊(duì)列中,然后循環(huán)調(diào)用postSingleEvent 函數(shù)發(fā)布隊(duì)列中的每個(gè)事件。

public void post(Object event) { 
PostingThreadState postingState = currentPostingThreadState.get(); 
List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event); 
if (!postingState.isPosting) { 
    postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper(); 
    postingState.isPosting = true; 
    if (postingState.canceled) { 
      throw new EventBusException("Internal error. Abort state was not reset"); 
    } try {
    while (!eventQueue.isEmpty()) { 
    postSingleEvent(eventQueue.remove(0), postingState); 
    } 
  } finally { 
    postingState.isPosting = false; 
    postingState.isMainThread = false; 
    } 
  } 
}

postToSubscription 函數(shù)中會(huì)判斷訂閱者的 ThreadMode,從而決定在什么 Mode 下執(zhí)行事件響應(yīng)函數(shù)。ThreadMode 共有四類:

  • PostThread:默認(rèn)的 ThreadMode,表示在執(zhí)行 Post 操作的線程直接調(diào)用訂閱者的事件響應(yīng)方法,不論該線程是否為主線程(UI 線程)。當(dāng)該線程為主線程時(shí),響應(yīng)方法中不能有耗時(shí)操作,否則有卡主線程的風(fēng)險(xiǎn)。適用場(chǎng)景:對(duì)于是否在主線程執(zhí)行無要求,但若 Post 線程為主線程,不能耗時(shí)的操作
  • MainThread:在主線程中執(zhí)行響應(yīng)方法。如果發(fā)布線程就是主線程,則直接調(diào)用訂閱者的事件響應(yīng)方法,否則通過主線程的 Handler 發(fā)送消息在主線程中處理——調(diào)用訂閱者的事件響應(yīng)函數(shù)。顯然,MainThread類的方法也不能有耗時(shí)操作,以避免卡主線程。適用場(chǎng)景:必須在主線程執(zhí)行的操作
  • BackgroundThread:在后臺(tái)線程中執(zhí)行響應(yīng)方法。如果發(fā)布線程不是主線程,則直接調(diào)用訂閱者的事件響應(yīng)函數(shù),否則啟動(dòng)唯一的后臺(tái)線程去處理。由于后臺(tái)線程是唯一的,當(dāng)事件超過一個(gè)的時(shí)候,它們會(huì)被放在隊(duì)列中依次執(zhí)行,因此該類響應(yīng)方法雖然沒有PostThread類和MainThread類方法對(duì)性能敏感,但最好不要有重度耗時(shí)的操作或太頻繁的輕度耗時(shí)操作,以造成其他操作等待。適用場(chǎng)景:操作輕微耗時(shí)且不會(huì)過于頻繁,即一般的耗時(shí)操作都可以放在這里;
  • Async:不論發(fā)布線程是否為主線程,都使用一個(gè)空閑線程來處理。和BackgroundThread不同的是,Async類的所有線程是相互獨(dú)立的,因此不會(huì)出現(xiàn)卡線程的問題。適用場(chǎng)景:長耗時(shí)操作,例如網(wǎng)絡(luò)訪問
post.png
5.unregister

通過typesBySubscriber來取出這個(gè)subscriber訂閱者訂閱的事件類型,從typesBySubscriber移除subscriber。

public synchronized void unregister(Object subscriber) { 
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); 
if (subscribedTypes != null) { 
    for (Class<?> eventType : subscribedTypes) { 
        unsubscribeByEventType(subscriber, eventType); 
    } 
  typesBySubscriber.remove(subscriber); 
} else { 
    Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass()); 
  } 
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • EventBus源碼分析(一) EventBus官方介紹為一個(gè)為Android系統(tǒng)優(yōu)化的事件訂閱總線,它不僅可以很...
    蕉下孤客閱讀 4,049評(píng)論 4 42
  • 面試有一種技巧據(jù)說叫做反客為主,當(dāng)遇到Activity-Fragment通信,甚至模塊化開發(fā)時(shí)的通信問題等等,可以...
    TruthKeeper閱讀 555評(píng)論 0 6
  • EventBus源碼分析(三) 在前面的兩篇文章中分別對(duì)EventBus中的構(gòu)建,分發(fā)事件以及注冊(cè)方法的查詢做了分...
    蕉下孤客閱讀 1,250評(píng)論 0 9
  • title: EventBus 源碼分析date: 2017-09-15 09:38:14tags: [Sourc...
    Passon_Fang閱讀 236評(píng)論 0 0
  • 【如果一睜眼就收到媽媽成長的喜訊,你一定會(huì)綻放心情,我很感謝接受我?guī)椭慕忝茫簌Z媽媽陪伴就是和你在一起感受生活】...
    企鵝媽媽閱讀 555評(píng)論 0 0