EventBus源碼分析

EventBus-Publish-Subscribe.png

簡述

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

基本使用

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

public class AnyEventType {  
 public AnyEventType(){}  
}  

2.注冊訂閱者

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)先級priority,而且方法名不在需要onEvent開頭,所以又簡潔靈活了不少.

5.解除注冊

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 新建一個 EventBus

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

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

register 函數(shù)中會先根據(jù)訂閱者類名去subscriberMethodFinder
中查找當(dāng)前訂閱者所有事件響應(yīng)函數(shù)盖淡,然后循環(huán)每一個事件響應(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)先級將當(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.檢查這個事件是否是 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ì)列中的每個事件城榛。

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ù)中會判斷訂閱者的 ThreadMode揪利,從而決定在什么 Mode 下執(zhí)行事件響應(yīng)函數(shù)。ThreadMode 共有四類:

  • PostThread:默認(rèn)的 ThreadMode狠持,表示在執(zhí)行 Post 操作的線程直接調(diào)用訂閱者的事件響應(yīng)方法疟位,不論該線程是否為主線程(UI 線程)。當(dāng)該線程為主線程時喘垂,響應(yīng)方法中不能有耗時操作甜刻,否則有卡主線程的風(fēng)險。適用場景:對于是否在主線程執(zhí)行無要求正勒,但若 Post 線程為主線程得院,不能耗時的操作
  • MainThread:在主線程中執(zhí)行響應(yīng)方法昭齐。如果發(fā)布線程就是主線程,則直接調(diào)用訂閱者的事件響應(yīng)方法矾柜,否則通過主線程的 Handler 發(fā)送消息在主線程中處理——調(diào)用訂閱者的事件響應(yīng)函數(shù)阱驾。顯然,MainThread類的方法也不能有耗時操作怪蔑,以避免卡主線程里覆。適用場景:必須在主線程執(zhí)行的操作
  • BackgroundThread:在后臺線程中執(zhí)行響應(yīng)方法缆瓣。如果發(fā)布線程不是主線程喧枷,則直接調(diào)用訂閱者的事件響應(yīng)函數(shù),否則啟動唯一的后臺線程去處理。由于后臺線程是唯一的隧甚,當(dāng)事件超過一個的時候车荔,它們會被放在隊(duì)列中依次執(zhí)行,因此該類響應(yīng)方法雖然沒有PostThread類和MainThread類方法對性能敏感戚扳,但最好不要有重度耗時的操作或太頻繁的輕度耗時操作忧便,以造成其他操作等待。適用場景:操作輕微耗時且不會過于頻繁帽借,即一般的耗時操作都可以放在這里珠增;
  • Async:不論發(fā)布線程是否為主線程,都使用一個空閑線程來處理砍艾。和BackgroundThread不同的是蒂教,Async類的所有線程是相互獨(dú)立的,因此不會出現(xiàn)卡線程的問題脆荷。適用場景:長耗時操作凝垛,例如網(wǎng)絡(luò)訪問
post.png
5.unregister

通過typesBySubscriber來取出這個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)容合作請聯(lián)系作者
  • 序言:七十年代末苔严,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子孤澎,更是在濱河造成了極大的恐慌届氢,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件覆旭,死亡現(xiàn)場離奇詭異退子,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)型将,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門寂祥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人七兜,你說我怎么就攤上這事丸凭。” “怎么了腕铸?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵惜犀,是天一觀的道長。 經(jīng)常有香客問我狠裹,道長虽界,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任涛菠,我火速辦了婚禮莉御,結(jié)果婚禮上撇吞,老公的妹妹穿的比我還像新娘。我一直安慰自己礁叔,他們只是感情好牍颈,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著晴圾,像睡著了一般颂砸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上死姚,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天人乓,我揣著相機(jī)與錄音,去河邊找鬼都毒。 笑死色罚,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的账劲。 我是一名探鬼主播戳护,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼瀑焦!你這毒婦竟也來了腌且?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤榛瓮,失蹤者是張志新(化名)和其女友劉穎铺董,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體禀晓,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡精续,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了粹懒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片重付。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖凫乖,靈堂內(nèi)的尸體忽然破棺而出确垫,到底是詐尸還是另有隱情,我是刑警寧澤帽芽,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布删掀,位于F島的核電站,受9級特大地震影響嚣镜,放射性物質(zhì)發(fā)生泄漏爬迟。R本人自食惡果不足惜橘蜜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一菊匿、第九天 我趴在偏房一處隱蔽的房頂上張望付呕。 院中可真熱鬧,春花似錦跌捆、人聲如沸徽职。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姆钉。三九已至,卻和暖如春抄瓦,著一層夾襖步出監(jiān)牢的瞬間潮瓶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工钙姊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留毯辅,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓煞额,卻偏偏與公主長得像思恐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子膊毁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

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

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