EventBus源碼解析(二)-EventBus實(shí)例化

一、默認(rèn)EventBus實(shí)例

當(dāng)某個(gè)類(lèi)需要訂閱事件時(shí),我們通常會(huì)先在這個(gè)類(lèi)的某處(如初始化方法)添加如下代碼以完成EventBus的注冊(cè)。

EventBus.getDefault().register(this);

然后在適當(dāng)?shù)牡胤教砑尤缦麓a以完成EventBus的注冊(cè)解除,防止泄露。

EventBus.getDefault().unregister(this);

無(wú)論是注冊(cè)或者解除注冊(cè),無(wú)一例外,都是通過(guò)EventBus.getDefault()獲取到的EventBus實(shí)例來(lái)完成的。那么getDefault()方法做了什么操作呢?我們跟進(jìn)代碼看看。

    public static EventBus getDefault() {
        EventBus instance = defaultInstance;
        if (instance == null) {
            synchronized (EventBus.class) {
                instance = EventBus.defaultInstance;
                if (instance == null) {
                    instance = EventBus.defaultInstance = new EventBus();
                }
            }
        }
        return instance;
    }

getDefault()方法其實(shí)很簡(jiǎn)單,就是使用單例模式,獲取到了唯一的EventBus對(duì)象。初次使用時(shí),instance對(duì)象勢(shì)必為null,此時(shí)就會(huì)通過(guò)EventBus的無(wú)參構(gòu)造函數(shù)創(chuàng)建出一個(gè)EventBus實(shí)例對(duì)象。無(wú)參構(gòu)造函數(shù)的實(shí)現(xiàn)如下:

    public EventBus() {
        this(DEFAULT_BUILDER);
    }

可以看到,EventBus的無(wú)參構(gòu)造函數(shù),最終調(diào)用的還是帶有單個(gè)參數(shù)的構(gòu)造函數(shù),其參數(shù)類(lèi)型是EventBusBuilder,望文生義,EventBusBuilder明顯是采用建造者模式實(shí)現(xiàn)的,這部分我們后面再分析。無(wú)參構(gòu)造函數(shù)調(diào)用了有參構(gòu)造函數(shù),并傳入了DEFAULT_BUILDER實(shí)參。那么,DEFAULT_BUILDER又是怎樣的呢?其實(shí)它就是一個(gè)EventBusBuilder對(duì)象,只有預(yù)設(shè)定的默認(rèn)配置。

 private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

DEFAULT_BUILDER傳入到有參的EventBus構(gòu)造函數(shù)后,會(huì)執(zhí)行一些初始化的工作,如下:

 EventBus(EventBusBuilder builder) {
        logger = builder.getLogger();
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadSupport = builder.getMainThreadSupport();
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        backgroundPoster = new BackgroundPoster(this);
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        eventInheritance = builder.eventInheritance;
        executorService = builder.executorService;
    }

在這里,會(huì)取出EventBusBuilder的各項(xiàng)配置值,賦值給相應(yīng)的EventBus中的成員。這是很典型的建造者模式,一般當(dāng)有多項(xiàng)配置時(shí),我們會(huì)考慮采用這種模式。

經(jīng)歷以上流程之后,默認(rèn)的EventBus實(shí)例就通過(guò)getDefault方法獲取到了,并且這個(gè)EventBus是全局唯一的。

代碼分析到這里,我們大概可以知道了,EventBus實(shí)例化可以有兩種方式:

  • 使用默認(rèn)的配置,即getDefault()方式
  • 使用EventBusBuilder自定義配置,之后通過(guò)build生成

二、默認(rèn)配置

EventBusBuilder是EventBus的建造者,負(fù)責(zé)初始化EventBus的各項(xiàng)配置,并生成EventBus對(duì)象。通過(guò)第一節(jié)的分析,我們會(huì)有一個(gè)疑問(wèn):EventBus的默認(rèn)配置到底是怎么樣的呢?這個(gè)問(wèn)題其實(shí)可以換個(gè)問(wèn)法:EventBusBuilder的默認(rèn)配置到底是怎么樣的呢?讓我們趕緊追進(jìn)代碼分析吧。

public class EventBusBuilder {
    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    boolean logSubscriberExceptions = true;
    boolean logNoSubscriberMessages = true;
    boolean sendSubscriberExceptionEvent = true;
    boolean sendNoSubscriberEvent = true;
    boolean throwSubscriberException;
    boolean eventInheritance = true;
    boolean ignoreGeneratedIndex;
    boolean strictMethodVerification;
    ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
    List<Class<?>> skipMethodVerificationForClasses;
    List<SubscriberInfoIndex> subscriberInfoIndexes;
    Logger logger;
    MainThreadSupport mainThreadSupport;

    ...
}

分析以上EventBusBuilder的成員及賦值,可以得出如下信息:

logSubscriberExceptions :是否打印訂閱者異常信息,默認(rèn)開(kāi)啟
logNoSubscriberMessages :某個(gè)事件沒(méi)有訂閱者時(shí),是否打印信息,默認(rèn)開(kāi)啟
sendSubscriberExceptionEvent :出現(xiàn)訂閱者異常時(shí),是否發(fā)送異常事件,默認(rèn)開(kāi)啟
sendNoSubscriberEvent :某個(gè)事件沒(méi)有訂閱者時(shí),是否發(fā)送無(wú)訂閱者的事件,默認(rèn)開(kāi)啟
throwSubscriberException :是否拋出訂閱者異常信息,默認(rèn)關(guān)閉
eventInheritance :事件是否可以繼承形式訂閱,默認(rèn)開(kāi)啟
ignoreGeneratedIndex :忽略索引生成,默認(rèn)關(guān)閉
strictMethodVerification :是否開(kāi)啟方法嚴(yán)格驗(yàn)證,默認(rèn)關(guān)閉
executorService :線程池,默認(rèn)是newCachedThreadPool,即沒(méi)有核心線程、但最大線程數(shù)是Integer.MAX_VALUE的線程池
skipMethodVerificationForClasses :跳過(guò)為訂閱者類(lèi)里面的方法進(jìn)行校驗(yàn),校驗(yàn)包括注解信息、修飾符是否是public且非static\final的,默認(rèn)為空
subscriberInfoIndexes :訂閱者信息索引,由注解處理器生成
mainThreadSupport :專(zhuān)為Android的主線程定制,持有主線程looper引用

結(jié)合第一節(jié)的分析,到這里我們可以得出結(jié)論,EventBus的默認(rèn)配置是:

  • 當(dāng)出現(xiàn)訂閱者異常時(shí),打印異常log
  • 當(dāng)事件沒(méi)有訂閱者時(shí),打印沒(méi)有訂閱者log
  • 當(dāng)出現(xiàn)訂閱者異常時(shí),發(fā)送異常事件
  • 當(dāng)事件沒(méi)有訂閱者時(shí),發(fā)送無(wú)訂閱者事件
  • 捕獲異常信息,防止崩潰
  • 事件可以繼承
  • 編譯時(shí)生成索引
  • 采用最大限制是Integer.MAX_VALUE的緩存線程池
  • 為每個(gè)訂閱者類(lèi)都進(jìn)行方法校驗(yàn)
  • 當(dāng)處于Android平臺(tái)時(shí),確??梢郧袚Q到主線程

三、自定義配置

那么如何進(jìn)行自定義的EventBus配置呢?聰明的你一定想到了。是的,我們可以通過(guò)EventBusBuilder來(lái)實(shí)現(xiàn)自定義配置。EventBusBuilder內(nèi)部提供了一系列的配置方法,方便用戶采用鏈?zhǔn)秸{(diào)用的方式,來(lái)生成一個(gè)EventBusBuilder對(duì)象。然而,通過(guò)查看EventBus源碼可知,EventBusBuilder的構(gòu)造方法的修飾符是protected的,也就是說(shuō),用戶無(wú)法通過(guò)直接new的方式來(lái)創(chuàng)建EventBusBuilder對(duì)象。這樣不就無(wú)法自定義配置了嗎?別急,雖然我們無(wú)法直接new出一個(gè)EventBusBuilder對(duì)象,但是EventBus類(lèi)提供了一個(gè)靜態(tài)方法builder(),該方法內(nèi)部默認(rèn)new了一個(gè)EventBusBuilder對(duì)象,如下:

    public static EventBusBuilder builder() {
        return new EventBusBuilder();
    }

通過(guò)builder()方法,用戶就可以獲取到EventBusBuilder對(duì)象,之后就可以隨心所欲地自定義配置了。配置有如下兩種使用姿勢(shì):

姿勢(shì)1:
        EventBus.builder().logNoSubscriberMessages(false)
                .logSubscriberExceptions(false).eventInheritance(false)...
                .installDefaultEventBus();
姿勢(shì)2:
              EventBus.builder().logNoSubscriberMessages(false)
                .logSubscriberExceptions(false).eventInheritance(false)...
                                .build();

上述兩種姿勢(shì)看起來(lái)非常相似,但其實(shí)是有區(qū)別的,區(qū)別就在于創(chuàng)建EventBus實(shí)例的方式,姿勢(shì)1使用的是installDefaultEventBus方法,姿勢(shì)2使用的是build方法。我們來(lái)看看這兩種方法的內(nèi)部實(shí)現(xiàn)。

    public EventBus installDefaultEventBus() {
        synchronized (EventBus.class) {
            if (EventBus.defaultInstance != null) {
                throw new EventBusException("Default instance already exists." +
                        " It may be only set once before it's used the first time to ensure consistent behavior.");
            }
            EventBus.defaultInstance = build();
            return EventBus.defaultInstance;
        }
    }
public EventBus build() {
        return new EventBus(this);
    }

看出區(qū)別了嗎?installDefaultEventBus方法在內(nèi)部其實(shí)也是調(diào)用的build方法,但不同的是,installDefaultEventBus可以確保EventBus實(shí)例的全局唯一性,當(dāng)defaultInstance非空時(shí),會(huì)直接拋出異常。而姿勢(shì)2直接使用build方法創(chuàng)建EventBus實(shí)例的方式,則需要用戶自身確保EventBus實(shí)例的全局唯一性。

EventBus并非一定要全局唯一,但確保全局唯一,不是可以更好更合理地管理和分發(fā)事件嗎?


四、結(jié)束語(yǔ)

通過(guò)以上幾小節(jié)的分析,我們已經(jīng)知道了EventBus的默認(rèn)配置情況,以及如何自定義配置。但如果再仔細(xì)觀察,會(huì)發(fā)現(xiàn),在 EventBus(EventBusBuilder builder) 構(gòu)造函數(shù)中,還默認(rèn)實(shí)例化了幾個(gè)成員對(duì)象:

        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();

        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        backgroundPoster = new BackgroundPoster(this);
        asyncPoster = new AsyncPoster(this);

        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);

這些成員是用來(lái)做什么的呢?我們先留個(gè)懸念,在后面的幾章中進(jìn)行詳細(xì)的分析。

?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,688評(píng)論 19 139
  • 前言 在上一篇文章:EventBus 3.0初探: 入門(mén)使用及其使用 完全解析中,筆者為大家介紹了EventBus...
    丶藍(lán)天白云夢(mèng)閱讀 15,995評(píng)論 21 128
  • 我每周會(huì)寫(xiě)一篇源代碼分析的文章,以后也可能會(huì)有其他主題.如果你喜歡我寫(xiě)的文章的話,歡迎關(guān)注我的新浪微博@達(dá)達(dá)達(dá)達(dá)s...
    SkyKai閱讀 25,177評(píng)論 23 184
  • 項(xiàng)目到了一定階段會(huì)出現(xiàn)一種甜蜜的負(fù)擔(dān):業(yè)務(wù)的不斷發(fā)展與人員的流動(dòng)性越來(lái)越大,代碼維護(hù)與測(cè)試回歸流程越來(lái)越繁瑣。這個(gè)...
    fdacc6a1e764閱讀 3,339評(píng)論 0 6
  • 2013年被稱為手游元年,但據(jù)Newzoo市場(chǎng)調(diào)查數(shù)據(jù)顯示,該年全球手游市場(chǎng)規(guī)模也不過(guò)175億美元,而2014年就...
    天之游閱讀 280評(píng)論 0 2

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