EventBus源碼分析-總覽全局

EventBus系列解析(基于3.2.0)

EventBus學(xué)習(xí)-基礎(chǔ)使用

EventBus源碼分析-總覽全局

在上一篇的《EventBus學(xué)習(xí)之基礎(chǔ)使用》中,主要對(duì)照著官方文檔介紹了EventBus的一些用法,本文將基于這些用法探究一下各個(gè)用法的實(shí)現(xiàn)細(xì)節(jié)。在使用EventBus時(shí),EventBus是一個(gè)必須使用的入口類,注冊(cè)/注銷訂閱者、發(fā)送事件都需要用到EventBus.getDefault(),本篇文章主要關(guān)注EventBus這個(gè)類本身,分析以下三個(gè)問題:

  • EventBus是什么?
  • 消息怎么來?
  • 消息到哪去?

EventBus是什么?

首先總覽EventBus這個(gè)類的聲明,并大概了解各個(gè)全局變量的作用:

public class EventBus {

    /** Log tag, apps may override it. */
    public static String TAG = "EventBus";

    // 全局靜態(tài)單例,即事件總線中的 總線
    static volatile EventBus defaultInstance;

    // 默認(rèn)的建造器
    private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
    // 事件類型緩存,key為某一事件的類型,value為該事件的所有父類及組件類型列表,用于事件可繼承時(shí)快速查找父類
    private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();// 

    // 訂閱者集合,key為事件類型,value為所有訂閱了該事件的訂閱者信息list
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    // 當(dāng)前訂閱者訂閱的所有事件集合,key為訂閱者對(duì)象,value為當(dāng)前訂閱者訂閱的所有事件集合
    private final Map<Object, List<Class<?>>> typesBySubscriber;
    // 粘滯事件集合
    private final Map<Class<?>, Object> stickyEvents;

    // 當(dāng)前執(zhí)行線程的狀態(tài) **ThreadLocal**
    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };

    // android主線程兼容配置,在非Android平臺(tái)為null
    // @Nullable
    private final MainThreadSupport mainThreadSupport;
    // android主線程事件執(zhí)行器,當(dāng)threadMode指定為ThreadMode.MAIN時(shí)會(huì)使用此執(zhí)行器調(diào)用訂閱者方法
    // @Nullable
    private final Poster mainThreadPoster;
    // 后臺(tái)執(zhí)行器,當(dāng)threadMode的值為 ThreadMode.BACKGROUND時(shí)會(huì)使用此執(zhí)行器調(diào)用訂閱者方法
    private final BackgroundPoster backgroundPoster;
    // 異步執(zhí)行器,當(dāng)threadMode的值為ThreadMode.ASYNC時(shí)會(huì)使用此執(zhí)行器調(diào)用訂閱者方法
    private final AsyncPoster asyncPoster;
    // 訂閱者方法查找器
    private final SubscriberMethodFinder subscriberMethodFinder;
    // 線程池,AsyncPoster 和 BackgroundPoster會(huì)使用此線程池調(diào)用訂閱者方法,默認(rèn)會(huì)new一個(gè)Executors.newCachedThreadPool(),
    private final ExecutorService executorService;

    // 是否拋出訂閱者方法調(diào)用異常,默認(rèn)為 false
    private final boolean throwSubscriberException;
    // 是否打印訂閱者方法調(diào)用異常信息,默認(rèn)為 true
    private final boolean logSubscriberExceptions;
    // 是否打印未找到訂閱者方法異常信息,默認(rèn)為 true
    private final boolean logNoSubscriberMessages;
    // 是否發(fā)送訂閱者方法調(diào)用異常事件,默認(rèn)為true,即當(dāng)發(fā)生訂閱者方法調(diào)用異常時(shí),會(huì)自動(dòng)發(fā)送一個(gè) SubscriberExceptionEvent
    private final boolean sendSubscriberExceptionEvent;
    // 是否發(fā)送未找到訂閱者方法異常事件,默認(rèn)為true,即當(dāng)發(fā)生訂閱者方法調(diào)用異常時(shí),會(huì)自動(dòng)發(fā)送一個(gè) NoSubscriberEvent
    private final boolean sendNoSubscriberEvent;
    // 事件是否可繼承,默認(rèn)為true,即如果事件A繼承了事件B,那么發(fā)送事件A時(shí),所有B事件的訂閱者也會(huì)被調(diào)用
    private final boolean eventInheritance;

    // 當(dāng)前總線已有的編譯時(shí)索引的個(gè)數(shù)
    private final int indexCount;
    private final Logger logger;
  
  // 方法省略。。。
}

所有的全局變量大概可以分為以下4部分

  • 靜態(tài)單例,整個(gè)框架就是通過這個(gè)靜態(tài)單例實(shí)現(xiàn)了全局的消息發(fā)送與接收
  • 訂閱者/粘滯消息 集合類,存儲(chǔ)了當(dāng)前總線所有的訂閱者和事件 的相關(guān)信息
  • 執(zhí)行器,用于在不同的線程調(diào)用訂閱者方法
  • 各種布爾變量標(biāo)志位

通過對(duì)EventBus所有的全局變量的了解分析,不難總結(jié)出它大概的運(yùn)行機(jī)制:

通過全局單例存儲(chǔ)了所有事件和訂閱者的集合,當(dāng)發(fā)送某個(gè)消息事件時(shí),通過查找這些集合找到所有的該事件的訂閱者,然后通過不同的執(zhí)行器在指定的線程調(diào)用訂閱者方法

接下來我們可以一步步的來驗(yàn)證上述的運(yùn)行機(jī)制,首先是全局單例

/** Convenience singleton for apps using a process-wide EventBus instance. */
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;
}

public EventBus() {
    this(DEFAULT_BUILDER);
}

由代碼可見,該全局單例采用雙重校驗(yàn)鎖實(shí)現(xiàn),但又不是嚴(yán)格意義上的單例模式,因?yàn)樗臉?gòu)造方法是用public修飾的,這就意味著我們可以自己構(gòu)造出新的EventBus對(duì)象,顯而易見,不同的EventBus對(duì)象之間是隔離的,即EventBus實(shí)例A發(fā)送的消息,并不能被EventBus實(shí)例B接收。

在對(duì)象的構(gòu)造上,為了簡(jiǎn)化構(gòu)造方法,采用了builder模式,同時(shí)通過這個(gè)EventBusBuilder我們也可以對(duì)EventBus的行為做一些定制,例如在上一篇EventBus學(xué)習(xí)之基礎(chǔ)使用中,在使用編譯時(shí)注解解釋器時(shí)我們就層生成過一個(gè)自己的EventBus對(duì)象,并將其設(shè)置為了默認(rèn)的總線對(duì)象

EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();

事實(shí)上通過builder我們還可以做更多的自定義行為:


image.png

從上面的方法中我們可以看出,EventBus的大部分屬性,都可以通過builder進(jìn)行自定義,在實(shí)際使用時(shí)可以根據(jù)需求進(jìn)行配置,不過需要強(qiáng)調(diào)的是,如果確認(rèn)需要做自定義配置,并且全局是通過EventBus.getDefault()使用,那么必須要在第一次調(diào)用getDefault方法之前調(diào)用EventBusBuilder的installDefaultEventBus()方法完成自定義配置,如果已經(jīng)存在了默認(rèn)實(shí)例再調(diào)用此方法,會(huì)直接拋出異常

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;
        }
    }

消息從哪來?

在使用時(shí),我們通常會(huì)調(diào)用以下代碼發(fā)送一個(gè)事件

EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

那么post(event)究竟做了什么呢?

/** Posts the given event to the event bus. */
    public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            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;
            }
        }
    }

代碼十分簡(jiǎn)單,首先通過ThreadLocal類型的對(duì)象currentPostingThreadState獲取了當(dāng)前線程的事件發(fā)送狀態(tài),這個(gè)狀態(tài)中存儲(chǔ)了以下信息

final static class PostingThreadState {
    final List<Object> eventQueue = new ArrayList<>(); // 待發(fā)送事件隊(duì)列
    boolean isPosting; // 是否正在發(fā)送事件
    boolean isMainThread;// 是否主線程
    Subscription subscription;// 當(dāng)前正在被調(diào)用的訂閱者相關(guān)信息
    Object event;// 當(dāng)前正在發(fā)送的事件對(duì)象
    boolean canceled;// 是否已取消發(fā)送
}

在將當(dāng)前事件對(duì)象加入到了待發(fā)送事件隊(duì)列中后,便通過while循環(huán)一直發(fā)送隊(duì)列中的事件

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

postSingleEvent方法中,首先拿到了被發(fā)送事件的Class類型,然后我們看到了一個(gè)熟悉的變量eventInheritance,這個(gè)在前面了解EventBus的全局變量時(shí)有說明了它代表的是 事件是否可繼承,在這我們可以看到,當(dāng)它是true時(shí),會(huì)直接通過lookupAllEventTypes()去查找當(dāng)前事件的所有父類,具體的查找邏輯為:優(yōu)先看當(dāng)前事件類的父類緩存是否存在于全局變量eventTypesCache中,如果不存在則通過clazz.getSuperclass()循環(huán)查找所有父類,通過clazz.getInterfaces()遞歸查找所有實(shí)現(xiàn)的接口,一直找到所有的父類和接口之后,刷新eventTypesCache并返回,然后從事件的本身到父類依次調(diào)用postSingleEventForEventType發(fā)送事件。
如果事件配置為不可繼承,邏輯更為簡(jiǎn)單,直接調(diào)用postSingleEventForEventType發(fā)送事件即可,postSingleEventForEventType的實(shí)現(xiàn)邏輯較為簡(jiǎn)單,直接找到了所有訂了了待發(fā)送事件的訂閱者,然后通過postToSubscription方法完成一次發(fā)送,

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
    CopyOnWriteArrayList<Subscription> subscriptions;
    synchronized (this) {
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    if (subscriptions != null && !subscriptions.isEmpty()) {
        for (Subscription subscription : subscriptions) {
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted;
            try {
                postToSubscription(subscription, event, postingState.isMainThread);
                aborted = postingState.canceled;
            } finally {
                postingState.event = null;
                postingState.subscription = null;
                postingState.canceled = false;
            }
            if (aborted) {
                break;
            }
        }
        return true;
    }
    return false;
}

由于篇幅所限,事件的發(fā)送流程暫時(shí)告一段落,后續(xù)的postToSubscription目前可以直接理解為在指定的線程中通過反射的方式調(diào)用了訂閱者的訂閱方法即可,一次完整的事件發(fā)送流程總結(jié)如下:

image.png

消息到哪去?

在上一節(jié)我們分析了事件的整個(gè)發(fā)送流程,本節(jié)主要分析事件發(fā)送之后,訂閱者是怎么接收到事件的,在使用EventBus時(shí),所有的訂閱者類都需要進(jìn)行2個(gè)操作,一個(gè)是 注冊(cè)/注銷,另一個(gè)是使用@Subscribe方法標(biāo)記響應(yīng)事件的方法,接下來首先來看一下注冊(cè)時(shí)發(fā)生了什么

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

代碼邏輯很簡(jiǎn)單,直接通過subscriberMethodFinder找到當(dāng)前對(duì)象的所有訂閱方法信息,具體的查找方式在使用篇里有介紹,默認(rèn)為采用反射的方式,如果配置了apt/kapt,則采用編譯時(shí)注解處理的方式生成訂閱者方法索引,在得到所有的訂閱者方法之后,又針對(duì)每個(gè)方法調(diào)用了subscribe方法

// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    Class<?> eventType = subscriberMethod.eventType;
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    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);
        }
    }

    int size = subscriptions.size();
    for (int i = 0; i <= size; i++) {
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }

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

    if (subscriberMethod.sticky) {
        if (eventInheritance) {
            // Existing sticky events of all subclasses of eventType have to be considered.
            // Note: Iterating over all events may be inefficient with lots of sticky events,
            // thus data structure should be changed to allow a more efficient lookup
            // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
            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);
        }
    }
}

代碼比較長(zhǎng),不過邏輯很簡(jiǎn)單,共做了以下幾件事

  • 維護(hù)全局的subscriptionsByEventTypekey-value集合,存儲(chǔ)所有訂閱者信息,key為事件類型,value為所有訂閱了該事件的訂閱者信息list,在向訂閱者信息list加入新的訂閱者時(shí),是按照method.priority屬性進(jìn)行排序的,以此實(shí)現(xiàn)了優(yōu)先級(jí)事件,保證高優(yōu)先級(jí)的訂閱者先收到事件
  • 維護(hù)全局的typesBySubscriberkey-value集合,這個(gè)集合存儲(chǔ)了訂閱者訂閱的所有事件集合,key為訂閱者對(duì)象,value為當(dāng)前訂閱者訂閱的所有事件集合
  • 維護(hù)全局的stickyEvents集合,這個(gè)集合存儲(chǔ)了所有的粘滯事件,此處有個(gè)小細(xì)節(jié),如果當(dāng)前訂閱者訂閱的是一個(gè)已存在的粘滯事件,那么需要立即響應(yīng)已存在的事件

總結(jié)一下,整個(gè)的訂閱者register的過程,其實(shí)就是對(duì)總線中幾個(gè)關(guān)鍵集合的數(shù)據(jù)維護(hù),在這幾個(gè)集合中存儲(chǔ)了所有訂閱者和事件的信息,通過這些信息,我們?cè)趐ost事件時(shí)才能將事件準(zhǔn)確的送到每一個(gè)訂閱者。

注銷時(shí)所作的操作與注冊(cè)時(shí)類似,只不過所有的操作都是相反的同樣也是維護(hù)了那幾個(gè)集合,只是都是做的相反的操作,將需要訂閱者的信息從集合中移除,特別的是stickyEvents集合需要另外調(diào)用removeStickyEvent進(jìn)行維護(hù)。

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

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

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