EventBus 3.1.1 源碼解析

本文要解決的問題

      1.什么是粘性事件?如何實(shí)現(xiàn)的渠脉?
      2.Eventbus內(nèi)部線程調(diào)度是如何實(shí)現(xiàn)的堤魁?

什么是粘性事件委乌?如何實(shí)現(xiàn)的添谊?

粘性事件,是指在發(fā)送事件之后再訂閱該事件也能收到該事件残制,這就使得我們可以預(yù)先處理一些事件立砸,讓有消費(fèi)者時(shí)再把這些事件投遞給消費(fèi)者.
           發(fā)送粘性事件
    public void sticky(View view) {
        EventBus.getDefault().postSticky(new EventBean("abc"));
    }

            接收粘性事件
    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void receiveSoundRecongnizedmsg(EventBean bean) {
          L.i(bean.getName());
    }

存儲粘性事件

  public void postSticky(Object event) {
        synchronized (stickyEvents) {
          //存儲
            stickyEvents.put(event.getClass(), event);
        }
        // Should be posted after it is putted, in case the subscriber wants to remove immediately
        post(event);
    }

通過源碼得知當(dāng)粘性事件發(fā)送之后就會被存儲到stickyEvents隊(duì)列里面,當(dāng)有相對應(yīng)的訂閱的時(shí)候才會收到粘性事件初茶。

         //當(dāng)訂閱的事件為粘性時(shí) 執(zhí)行以下方法
        if (subscriberMethod.sticky) {
            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();
                        //執(zhí)行對應(yīng)的訂閱方法
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }

當(dāng)訂閱方法颗祝,粘性參數(shù)為true的時(shí)候,會去檢索粘性事件存儲隊(duì)列恼布,當(dāng)隊(duì)列有匹配的對象的時(shí)候執(zhí)行訂閱方法螺戳。

 public boolean removeStickyEvent(Object event) {
        synchronized (stickyEvents) {
            Class<?> eventType = event.getClass();
            Object existingEvent = stickyEvents.get(eventType);
            if (event.equals(existingEvent)) {
                stickyEvents.remove(eventType);
                return true;
            } else {
                return false;
            }
        }
    }

移除粘性事件(當(dāng)粘性事件處理過之后,需移除粘性事件折汞,否則這個(gè)事件會一直存儲在隊(duì)列里面倔幼,每次啟動都會執(zhí)行訂閱方法)
我們看到移除粘性事件方法是從stickyEvents隊(duì)列里面找到匹配的對象,然后移除爽待,此事件就不會被重復(fù)執(zhí)行了损同。

Eventbus內(nèi)部線程調(diào)度是如何實(shí)現(xiàn)的?

public enum ThreadMode {
     // 事件的處理和事件的發(fā)送在相同的進(jìn)程
    POSTING,
    //事件的處理會在UI線程執(zhí)行
    MAIN,
    //后臺進(jìn)程鸟款,處理如保存到數(shù)據(jù)庫
    BACKGROUND
    //異步執(zhí)行膏燃,另起線程操作,事件的處理會在單獨(dú)的線程執(zhí)行何什,主要用于后臺線程中耗時(shí)操作
    ASYNC
}

我們知道eventbus的訂閱方法有以上四種線程模式组哩,那么event是如何從發(fā)送者的線程切換到接收方的線程的呢。

  private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    //從子線程切換到主線程
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    // 從主線程切切換到子線程
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC:
              //另起子線程
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }

由此可以得知eventbus是通過 mainThreadPoster; backgroundPoster; asyncPoster的enqueue方法進(jìn)行線程調(diào)度的。

public class HandlerPoster extends Handler implements Poster {}

final class BackgroundPoster implements Runnable, Poster {}

class AsyncPoster implements Runnable, Poster {}

通過上面代碼我們可以得知 mainThreadPoster; backgroundPoster; asyncPoster這三個(gè)類分別繼承自Handler Runnable Runnable伶贰,也就是說EventBus線程切換底層是通過Handle的handleMessage()方法回到主線程蛛砰,通過Runnable的run方法切到子線程。

至此我們已經(jīng)解決以上兩個(gè)問題幕袱。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末暴备,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子们豌,更是在濱河造成了極大的恐慌,老刑警劉巖浅妆,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件望迎,死亡現(xiàn)場離奇詭異,居然都是意外死亡凌外,警方通過查閱死者的電腦和手機(jī)辩尊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來康辑,“玉大人摄欲,你說我怎么就攤上這事〈保” “怎么了胸墙?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長按咒。 經(jīng)常有香客問我迟隅,道長,這世上最難降的妖魔是什么励七? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任智袭,我火速辦了婚禮,結(jié)果婚禮上掠抬,老公的妹妹穿的比我還像新娘吼野。我一直安慰自己,他們只是感情好两波,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布瞳步。 她就那樣靜靜地躺著,像睡著了一般雨女。 火紅的嫁衣襯著肌膚如雪谚攒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天氛堕,我揣著相機(jī)與錄音馏臭,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛括儒,可吹牛的內(nèi)容都是我干的绕沈。 我是一名探鬼主播,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼帮寻,長吁一口氣:“原來是場噩夢啊……” “哼乍狐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起固逗,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤浅蚪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后烫罩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惜傲,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年贝攒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盗誊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,687評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡隘弊,死狀恐怖哈踱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情梨熙,我是刑警寧澤开镣,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布,位于F島的核電站串结,受9級特大地震影響哑子,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肌割,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一卧蜓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧把敞,春花似錦弥奸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至耽装,卻和暖如春愤炸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掉奄。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工规个, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓诞仓,卻偏偏與公主長得像缤苫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子墅拭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,576評論 2 349