Android 事件總線 EventBus 源碼解析

大家好邮绿,自我介紹一下床未,我是 N0tExpectErr0r飘庄,一個(gè)還在讀大學(xué)的 Android 開發(fā)者炕柔,之前的大部分博客都發(fā)布在了自己的個(gè)人博客中酌泰,從今天開始在簡書也進(jìn)行博客的更新,歡迎各位關(guān)注

之前寫過了很多常用的庫的源碼解析匕累,但都需要大量參考其他大牛的博客才能徹底理解一個(gè)庫的原理×晟玻現(xiàn)在想檢驗(yàn)一下自己的代碼閱讀能力,因此嘗試靠自己去獨(dú)立地完成一篇源碼解析欢嘿,看看效果如何衰琐。我們先從 EventBus 入手,這篇文章分析的 EventBus 版本為 3.1.1炼蹦。

getDefault 方法

我們先從 EventBus 的入口羡宙,getDefalut 方法入手:


public static EventBus getDefault() {

    if (defaultInstance == null) {

        synchronized (EventBus.class) {

            if (defaultInstance == null) {

                defaultInstance = new EventBus();

            }

        }

    }

    return defaultInstance;

}

從 getDefault 方法可以看出,EventBus 類是一個(gè)采用了 Double Check 的單例類框弛。

我們接下來看到它的構(gòu)造函數(shù)辛辨,它的無參構(gòu)造函數(shù) EventBus() 實(shí)際上是調(diào)用了 EventBus(EventBusBuilder) 這個(gè)有參構(gòu)造函數(shù)的,傳入的參數(shù)是 DEFAULT_BUILDER瑟枫,而 DEFAULT_BUILDER 則是一個(gè)調(diào)用了 EventBusBuilder 默認(rèn)構(gòu)造器的對象斗搞。可以看出慷妙,這里用到了 Builder 模式來支持用 EventBusBuilder 進(jìn)行一些配置僻焚。

下面我們看到 EventBus(EventBusBuilder):


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;

}

這個(gè)構(gòu)造方法中主要進(jìn)行的是一些容器的初始化以及將一些配置參數(shù)從 Builder 中取出。

register 方法

下面我們再從 register 方法的角度進(jìn)行分析膝擂,看看 EventBus 在我們進(jìn)行 register 時(shí)做了一些什么事:


public void register(Object subscriber) {

    Class<?> subscriberClass = subscriber.getClass();

    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);

    synchronized (this) {

        for (SubscriberMethod subscriberMethod : subscriberMethods) {

            subscribe(subscriber, subscriberMethod);

        }

    }

}

register 傳入的 register 是一個(gè) Object 類型虑啤,也就是任意類都可以向 EventBus 進(jìn)行 register隙弛。它首先獲取到了 subscriber 的類型信息,然后將其傳遞給了 subscriberMethodFinder 的 findSubscriberMethods() 方法狞山。

通過名稱可以很容易看出全闷,SubscriberMethodFinder 類是一個(gè)專門用來搜尋 subscriber 中含有 @Subscribe 注解的方法的類。這里進(jìn)行的操作就是將所有被 @Subscribe 標(biāo)記的方法都加入到 List 中萍启。

而在找到了這些方法后总珠,則一個(gè)個(gè)進(jìn)行遍歷,并將其執(zhí)行 subscribe操作勘纯。

也就是說 register 可以分為兩部分來看——搜尋訂閱

搜尋過程

我們先進(jìn)入 findSubscriberMethods() 看看它的搜尋過程


List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {

    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);

    if (subscriberMethods != null) {

        return subscriberMethods;

    }

    if (ignoreGeneratedIndex) { // 1

        subscriberMethods = findUsingReflection(subscriberClass);

    } else {

        subscriberMethods = findUsingInfo(subscriberClass);

    }

    if (subscriberMethods.isEmpty()) {

        throw new EventBusException("Subscriber " + subscriberClass

                + " and its super classes have no public methods with the @Subscribe annotation");

    } else {

        METHOD_CACHE.put(subscriberClass, subscriberMethods);

        return subscriberMethods;

    }

}

可以分別看到 1 和 2 處的 if 語句局服,在 ignoreGeneratedIndex 為 true 時(shí),調(diào)用了 findUsingReflection 來使用反射搜尋方法驳遵。反之則調(diào)用了 findUsingInfo 方法進(jìn)行搜尋淫奔。ignoreGenereatedIndex 是用于標(biāo)記是否忽略由 Builder 傳入的 SubscriberInfoIndex。

直接搜尋


private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {

    FindState findState = prepareFindState();

    findState.initForSubscriber(subscriberClass);

    while (findState.clazz != null) {

        findUsingReflectionInSingleClass(findState);

        findState.moveToSuperclass();

    }

    return getMethodsAndRelease(findState);

}

可以看出堤结,搜尋過程的結(jié)果是用了一個(gè)名為 FindState 的類進(jìn)行存儲的唆迁,它是 SubscriberMethodFinder 的一個(gè)內(nèi)部類。我們重點(diǎn)關(guān)注的是這里的 while 循環(huán)霍殴,它先執(zhí)行了 findUsingReflectionInSingleClass 方法通過反射找到所有被 @Subscribe 標(biāo)注的方法媒惕,再通過 moveToSuperclass 向這個(gè)類的父類進(jìn)行搜尋系吩。

查找

我們看到 findUsingReflectionInSingleClass 的實(shí)現(xiàn):


private void findUsingReflectionInSingleClass(FindState findState) {

    Method[] methods;

    try {

        // This is faster than getMethods, especially when subscribers are fat classes like Activities

        methods = findState.clazz.getDeclaredMethods();

    } catch (Throwable th) {

        // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149

        methods = findState.clazz.getMethods();

        findState.skipSuperClasses = true;

    }

    for (Method method : methods) {

        int modifiers = method.getModifiers();

        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {

            Class<?>[] parameterTypes = method.getParameterTypes();

            if (parameterTypes.length == 1) {

                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);

                if (subscribeAnnotation != null) {

                    Class<?> eventType = parameterTypes[0];

                    if (findState.checkAdd(method, eventType)) {

                        ThreadMode threadMode = subscribeAnnotation.threadMode();

                        findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,

                                subscribeAnnotation.priority(), subscribeAnnotation.sticky()));

                    }

                }

            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {

                String methodName = method.getDeclaringClass().getName() + "." + method.getName();

                throw new EventBusException("@Subscribe method " + methodName +

                        "must have exactly 1 parameter but has " + parameterTypes.length);

            }

        } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {

            String methodName = method.getDeclaringClass().getName() + "." + method.getName();

            throw new EventBusException(methodName +

                    " is a illegal @Subscribe method: must be public, non-static, and non-abstract");

        }

    }

}

這里的代碼比較長来庭,我們慢慢分析。

首先進(jìn)行的是 Method 列表的獲取穿挨。這里通過注釋可以看出月弛,使用 getDeclaredMethods() 方法其實(shí)是比 getMethods() 方法的效率更高的,但有時(shí)會導(dǎo)致 NoClassDefFoundError科盛,此時(shí)采取備用方案帽衙,使用 getMethods() 進(jìn)行獲取。

之后遍歷 Method 數(shù)組贞绵,其中進(jìn)行了兩次校驗(yàn):第一次校驗(yàn)用于檢查被 @Subscribe 修飾的方法是否是 public厉萝、non-static、non-abstract 的榨崩。第二次檢查則是檢查其參數(shù)個(gè)數(shù)是否符合 1 的要求谴垫。當(dāng)不滿足時(shí)會拋出對應(yīng)異常,而滿足要求則會進(jìn)行 @Subscribe 注解的搜索母蛛。

當(dāng)找到了對應(yīng)注解后會進(jìn)行一次 checkAdd翩剪,在這個(gè)方法中會將 方法及其對應(yīng)的 Event 放入一個(gè) HashMap anyMethodByEventType,同時(shí)還會將方法的簽名(形式為 方法名>Event 類型名)及對應(yīng)方法放入另一個(gè) HashMap subscriberClassByMethodKey彩郊。

當(dāng) checkAdd 檢查沒有放入過這個(gè)方法及 Event 后前弯,就會將方法的信息包裝為一個(gè) SubscriberMethod 類蚪缀,然后放入我們需要的結(jié)果列表。

向上查找

當(dāng)查找完成后恕出,會向調(diào)用 moveToSuperclass 方法向其父類進(jìn)行查詢询枚,直到遇到了系統(tǒng)提供的庫。通過這種向上查找的方式可以使得 EventBus 支持繼承這一 OOP 特性浙巫。


void moveToSuperclass() {

    if (skipSuperClasses) {

        clazz = null;

    } else {

        clazz = clazz.getSuperclass();

        String clazzName = clazz.getName();

        /** Skip system classes, this just degrades performance. */

        if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {

            clazz = null;

        }

    }

}

非直接搜尋

下面我們看到搜尋過程的另一種實(shí)現(xiàn):


private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {

    FindState findState = prepareFindState();

    findState.initForSubscriber(subscriberClass);

    while (findState.clazz != null) {

        findState.subscriberInfo = getSubscriberInfo(findState);

        if (findState.subscriberInfo != null) {

            SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();

            for (SubscriberMethod subscriberMethod : array) {

                if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {

                    findState.subscriberMethods.add(subscriberMethod);

                }

            }

        } else {

            findUsingReflectionInSingleClass(findState);

        }

        findState.moveToSuperclass();

    }

    return getMethodsAndRelease(findState);

}

這里可以看到哩盲,先通過 getSubscriberInfo 獲取到了由 Builder 過程傳入的 SubscriberInfoIndex,從中獲取需要的信息狈醉。當(dāng)其值為 null 時(shí)廉油,再使用反射搜尋的方式進(jìn)行搜尋。

而具體添加過程苗傅,則與直接搜尋中的方式類似抒线,這里不再贅述。

FindState 復(fù)用

這里要注意渣慕,無論是直接搜索還是非直接搜索嘶炭,它們所使用的 FindState 都是通過 prepareFindState() 來進(jìn)行獲取,同時(shí)逊桦,它們的結(jié)果最后都會通過 getMethodsAndRelease(findState) 來進(jìn)行返回眨猎。其實(shí) SubscriberMethodFinder 類中維護(hù)了一個(gè) FindState 池,是一個(gè)默認(rèn)大小為 4 的數(shù)組强经,在 prepareFindState 中會遍歷數(shù)組找到非 null 的 FindState 進(jìn)行返回睡陪。而在 getMethodsAndRelease(findState) 中則是將搜尋的結(jié)果取出后,對 FindState 進(jìn)行 recycle匿情,之后再將其放回 FindState 池中兰迫。這種池的復(fù)用思想非常值得我們在設(shè)計(jì)庫的時(shí)候?qū)W習(xí)。

訂閱過程

我們回到 register 方法中來:


public void register(Object subscriber) {

    Class<?> subscriberClass = subscriber.getClass();

    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);

    synchronized (this) {

        for (SubscriberMethod subscriberMethod : subscriberMethods) {

            subscribe(subscriber, subscriberMethod);

        }

    }

}

可以看到 EventBus 為方法的訂閱過程進(jìn)行了加鎖炬称,保證了線程安全汁果。然后遍歷了每一個(gè)被標(biāo)記的方法,一一將其訂閱玲躯。

下面我們看看具體的訂閱流程据德,進(jìn)入 subscribe 方法:


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

        }

    }

}

這里的代碼也是很長...讓我們慢慢進(jìn)行分析。

先看看 Subcription跷车,它就是一個(gè)將 Subcriber 及 SubcriberMethod 進(jìn)行包裝的類棘利。

首先,這個(gè)方法進(jìn)行了一個(gè)安全檢查姓赤,檢查了同樣的方法是否已經(jīng)被注冊過赡译,沒有則將其放入 Map 中,否則拋出異常不铆。

之后再將其按照優(yōu)先級放入以該 Event 為參數(shù)的方法列表中蝌焚。

然后裹唆,又將這個(gè)方法加入了以該 Subcriber 為 key,以它內(nèi)部所有被 @Subscribe 標(biāo)記的方法的列表為 value 的 Map typesBySubscriber中只洒。

最后许帐,進(jìn)行了一個(gè)對 sticky 事件的特殊處理,如果為 sticky 事件則會在 register 時(shí)進(jìn)行一次對 Method 的調(diào)用毕谴。主要邏輯是:首先判斷了 Event 是否子 Event成畦,若是一個(gè)子 Event 則找到其父 Event 作為參數(shù) Event,否則將其作為參數(shù) Event涝开,然后在判 null 的情況下調(diào)用 postToSubscription 方法來執(zhí)行這個(gè)方法循帐。關(guān)于具體的執(zhí)行過程,會在下文中進(jìn)行講解舀武。

post 方法

post 方法開始拄养,就會涉及我們的 Event 的執(zhí)行過程了。這里根據(jù) register 的分析過程可以大概猜出方法應(yīng)該是由反射的方式被執(zhí)行的银舱,下面讓我們進(jìn)入 post 方法的源碼看看是否是這樣:


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;

        }

    }

}

存放線程信息

首先瘪匿,它獲取到了 currentPostingThreadState 這一個(gè)對象,它的類型是 PostingThreadState寻馏,這個(gè)類的主要用途是記錄事件的發(fā)布者的線程信息棋弥。


final static class PostingThreadState {

    final List<Object> eventQueue = new ArrayList<>();

    boolean isPosting;

    boolean isMainThread;

    Subscription subscription;

    Object event;

    boolean canceled;

}

我們看到 currentPostingThreadState 的創(chuàng)建過程:


private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {

    @Override

    protected PostingThreadState initialValue() {

        return new PostingThreadState();

    }

};

這里可以看到 currentPostingThreadState 是通過 ThreadLocal 進(jìn)行保存。ThreadLocal 是一個(gè)用于創(chuàng)建線程局部變量的類诚欠。它創(chuàng)建的變量只能被當(dāng)前線程訪問顽染,其他線程則無法訪問和修改。

之后在 post 中進(jìn)行的操作就是為 currentPostingThreadState 填充各種線程相關(guān)信息了聂薪。


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;

    }

}

我們回到 post 中家乘,可以發(fā)現(xiàn)蝗羊,在 currentPostingThreadState 中維護(hù)了一個(gè) eventQueue藏澳。

首先,將 Event 插入了 eventQueue 中耀找,之后將 isMainThread 等信息進(jìn)行填充翔悠。同時(shí)將 postingState 的 isPosting 置為了 true,使得事件 post 的過程中當(dāng)前線程的其他 post 事件無法被相應(yīng)野芒,當(dāng) post 過程結(jié)束后蓄愁,再將其置為 true。

之后狞悲,便開始遍歷 eventQueue, 將事件一個(gè)個(gè)出隊(duì)并執(zhí)行 postSingleEvent 方法撮抓,接下來我們看到 postSingleEvent 方法:


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

        }

    }

}

可以看到,這里通過 postSingleEventForEventType 來進(jìn)行搜尋對應(yīng) Subscription摇锋,如果 Event 是子 Event丹拯,則獲取它的所有父 Event 列表站超,再遍歷列表進(jìn)行搜尋。否則直接調(diào)用 postSingleEventForEventType 進(jìn)行搜尋乖酬。

搜尋 Subscription

下面我們看到 postSingleEventForEventType:


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 = false;

            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;

}

首先死相,這里根據(jù) event 找到了所有對應(yīng)的 Subscription,然后遍歷 subscription 列表調(diào)用 postToSubscription() 方法咬像,這個(gè)方法在之前 register 的分析中針對 sticky 事件的代碼中也有調(diào)用算撮,它的作用是調(diào)用 event 對應(yīng)的方法。

未找到對應(yīng) Subscription 的處理

我們在這里先不關(guān)心 postToSubscription 的具體實(shí)現(xiàn)县昂,先看看在 Subscription 調(diào)用結(jié)束后做了什么事肮柜,我們回到 postSingleEvent 方法中:


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

    }

}

可以看到,如果在沒有找到對應(yīng)的 subscription倒彰,則會創(chuàng)建一個(gè) NoSubscriberEvent 再調(diào)用 post 請求素挽。這樣,無論 Event 是否有 Subscriber狸驳,它都會進(jìn)行一次檢測预明。

執(zhí)行對應(yīng) Subscription

下面我們看到 postToSubscription,看看是如何調(diào)用 Event 對應(yīng)的方法的:


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

    }

}

可以看到耙箍,這里對訂閱者的線程進(jìn)行了判斷撰糠,采用不同的 Poster 進(jìn)行入隊(duì)操作,采用隊(duì)列的方式一一處理辩昆。對某些特殊情況則直接調(diào)用 invokeSubscriber(subscription, event) 進(jìn)行處理阅酪。關(guān)于 Poster 的設(shè)計(jì)我們在之后進(jìn)行分析,在 Poster 內(nèi)部調(diào)用的是 invokeSubscriber(PendingPost) 方法汁针。

invokeSubscriber(subscription, event)

我們先看到 invokeSubscriber(subscription, event) 方法:


void invokeSubscriber(Subscription subscription, Object event) {

    try {

        subscription.subscriberMethod.method.invoke(subscription.subscriber, event);

    } catch (InvocationTargetException e) {

        handleSubscriberException(subscription, event, e.getCause());

    } catch (IllegalAccessException e) {

        throw new IllegalStateException("Unexpected exception", e);

    }

}

果然术辐,如我們之前猜測的一樣,它是通過反射來對方法進(jìn)行調(diào)用的施无,代碼很簡單辉词,就不再贅述了。

invokeSubscriber(PendingPost)

下面我們看到 invokeSubscriber(PendingPost) 方法:


void invokeSubscriber(PendingPost pendingPost) {

    Object event = pendingPost.event;

    Subscription subscription = pendingPost.subscription;

    PendingPost.releasePendingPost(pendingPost);

    if (subscription.active) {

        invokeSubscriber(subscription, event);

    }

}

可以看到猾骡,它在內(nèi)部判斷了 Subscription 的 active 狀態(tài)瑞躺,如果為 active,再調(diào)用 invokeSubscriber(subscription, event) 方法對 Method 進(jìn)行執(zhí)行兴想。

這個(gè) active 狀態(tài)可以使得 unregister 的類中的對應(yīng) Method 不再被執(zhí)行幢哨。

postSticky 方法

這時(shí)你可能會想到,還有一個(gè)方法 postSticky 呢嫂便,我們接下來看到 postSticky 方法:


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

}

這里的邏輯十分簡單捞镰,先將 event 加入 stickyEvents 列表,再執(zhí)行 post 請求。

unregister 方法

我們接著看到 unregister 方法:


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 {

        logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());

    }

}

unregister 方法相對比較簡單岸售,首先它先判斷了這個(gè) Event 是否還未注冊几迄,若已注冊則遍歷在 typesBySubscriber 中 Subscriber 所對應(yīng)的每一個(gè) EventType,并一一對其執(zhí)行 unsubscribeByEventType 方法取消訂閱冰评,同時(shí) Subcriber 所對應(yīng)的信息從 typesBySubscriber 這個(gè) Map 中移除映胁。

下面我們看看 unsubscribeByEventType 中具體做了什么:


private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {

    List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);

    if (subscriptions != null) {

        int size = subscriptions.size();

        for (int i = 0; i < size; i++) {

            Subscription subscription = subscriptions.get(i);

            if (subscription.subscriber == subscriber) {

                subscription.active = false;

                subscriptions.remove(i);

                i--;

                size--;

            }

        }

    }

}

可以看到,它是將 subscriptionsByEventType 中與 EventType 對應(yīng)的 Subscription 列表取出甲雅,遍歷并將該 Subcriber 對應(yīng)的 Subscription 的 active 標(biāo)記為 false 并刪除解孙。

Poster

前面提到了 post 方法中會用到 Poster 來進(jìn)行方法的按隊(duì)列執(zhí)行,EventBus 中定義了一種 Poster 這個(gè)接口抛人,用于處理 post 后方法執(zhí)行的調(diào)度弛姜。


/**

* Posts events.

*

* @author William Ferguson

*/

interface Poster {

    /**

    * Enqueue an event to be posted for a particular subscription

    *

    * @param subscription Subscription which will receive the eve

    * @param event        Event that will be posted to subscriber

    */

    void enqueue(Subscription subscription, Object event);

}

可以看到,它內(nèi)部只有一個(gè)方法 enqueue妖枚,用于將 Event 放入待定隊(duì)列廷臼。

在 EventBus 中的 Poster 用到了三種,我們分別介紹:

HandlerPoster

HandlerPoster 是默認(rèn)情況下 mainThreadPoster 的類型绝页,它的內(nèi)部是使用 Handler 實(shí)現(xiàn)進(jìn)程的調(diào)度荠商,主要關(guān)注其 handleMessage 的實(shí)現(xiàn):


@Override

public void handleMessage(Message msg) {

    boolean rescheduled = false;

    try {

        long started = SystemClock.uptimeMillis();

        while (true) {

            PendingPost pendingPost = queue.poll();

            if (pendingPost == null) {

                synchronized (this) {

                    // Check again, this time in synchronized

                    pendingPost = queue.poll();

                    if (pendingPost == null) {

                        handlerActive = false;

                        return;

                    }

                }

            }

            eventBus.invokeSubscriber(pendingPost);

            long timeInMethod = SystemClock.uptimeMillis() - started;

            if (timeInMethod >= maxMillisInsideHandleMessage) {

                if (!sendMessage(obtainMessage())) {

                    throw new EventBusException("Could not send handler message");

                }

                rescheduled = true;

                return;

            }

        }

    } finally {

        handlerActive = rescheduled;

    }

}

可以看到,內(nèi)部是通過一個(gè)死循環(huán)遍歷 PendingPost 的隊(duì)列续誉,分別對其執(zhí)行 invokeSubscriber莱没。

AsyncPoster

AsyncPoster 對應(yīng)了 EventBus 中的 asyncPoster,下面是它的代碼:


class AsyncPoster implements Runnable, Poster {

    private final PendingPostQueue queue;

    private final EventBus eventBus;

    AsyncPoster(EventBus eventBus) {

        this.eventBus = eventBus;

        queue = new PendingPostQueue();

    }

    public void enqueue(Subscription subscription, Object event) {

        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);

        queue.enqueue(pendingPost);

        eventBus.getExecutorService().execute(this);

    }

    @Override

    public void run() {

        PendingPost pendingPost = queue.poll();

        if(pendingPost == null) {

            throw new IllegalStateException("No pending post available");

        }

        eventBus.invokeSubscriber(pendingPost);

    }

}

它的代碼很簡單酷鸦,通過 EventBus 的線程池中取出一個(gè)線程并在該線程中調(diào)用 invokeSubscriber 方法饰躲。

BackgroundPoster

BackgroundPoster 對應(yīng) EventBus 中的 backgroundPoster,下面是它的代碼:


final class BackgroundPoster implements Runnable, Poster {

    private final PendingPostQueue queue;

    private final EventBus eventBus;

    private volatile boolean executorRunning;

    BackgroundPoster(EventBus eventBus) {

        this.eventBus = eventBus;

        queue = new PendingPostQueue();

    }

    public void enqueue(Subscription subscription, Object event) {

        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);

        synchronized (this) {

            queue.enqueue(pendingPost);

            if (!executorRunning) {

                executorRunning = true;

                eventBus.getExecutorService().execute(this);

            }

        }

    }

    @Override

    public void run() {

        try {

            try {

                while (true) {

                    PendingPost pendingPost = queue.poll(1000);

                    if (pendingPost == null) {

                        synchronized (this) {

                            // Check again, this time in synchronized

                            pendingPost = queue.poll();

                            if (pendingPost == null) {

                                executorRunning = false;

                                return;

                            }

                        }

                    }

                    eventBus.invokeSubscriber(pendingPost);

                }

            } catch (InterruptedException e) {

                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);

            }

        } finally {

            executorRunning = false;

        }

    }

}

這段代碼比較長臼隔,和 AsyncPoster 有些類似嘹裂,它使用了 synchronized 以保證線程安全,在 run 方法中遍歷了 PendingPost 列表摔握,取出并執(zhí)行 Event寄狼。

PendingPost 池

PendingPost 內(nèi)部也是維護(hù)了一個(gè) PendingPost 池的,上面的幾個(gè) Poster 都是調(diào)用 PendingPost.obtainPendingPost 方法從其中取出 PendingPost盒发,它的代碼如下:


final class PendingPost {

    private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();

    Object event;

    Subscription subscription;

    PendingPost next;

    private PendingPost(Object event, Subscription subscription) {

        this.event = event;

        this.subscription = subscription;

    }

    static PendingPost obtainPendingPost(Subscription subscription, Object event) {

        synchronized (pendingPostPool) {

            int size = pendingPostPool.size();

            if (size > 0) {

                PendingPost pendingPost = pendingPostPool.remove(size - 1);

                pendingPost.event = event;

                pendingPost.subscription = subscription;

                pendingPost.next = null;

                return pendingPost;

            }

        }

        return new PendingPost(event, subscription);

    }

    static void releasePendingPost(PendingPost pendingPost) {

        pendingPost.event = null;

        pendingPost.subscription = null;

        pendingPost.next = null;

        synchronized (pendingPostPool) {

            // Don't let the pool grow indefinitely

            if (pendingPostPool.size() < 10000) {

                pendingPostPool.add(pendingPost);

            }

        }

    }

}

原理比較簡單例嘱,就不再分析了。

總結(jié)

通過這次源碼解析宁舰,收獲了很多,果然還是自己去看源碼才能對這些庫有更深層的了解奢浑。

EventBus 實(shí)際上就是一個(gè)基于反射實(shí)現(xiàn)的『公告牌』蛮艰,發(fā)布者可以將各種類型的公告放置到公告牌中,而訂閱者可以訂閱某種類型的公告雀彼,當(dāng)公告牌上出現(xiàn)了這種類型的公告時(shí)壤蚜,便會從上面取出并通知訂閱者即寡。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市袜刷,隨后出現(xiàn)的幾起案子聪富,更是在濱河造成了極大的恐慌,老刑警劉巖著蟹,帶你破解...
    沈念sama閱讀 222,946評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件墩蔓,死亡現(xiàn)場離奇詭異,居然都是意外死亡萧豆,警方通過查閱死者的電腦和手機(jī)奸披,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涮雷,“玉大人阵面,你說我怎么就攤上這事『檠迹” “怎么了样刷?”我有些...
    開封第一講書人閱讀 169,716評論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長览爵。 經(jīng)常有香客問我颂斜,道長,這世上最難降的妖魔是什么拾枣? 我笑而不...
    開封第一講書人閱讀 60,222評論 1 300
  • 正文 為了忘掉前任沃疮,我火速辦了婚禮,結(jié)果婚禮上梅肤,老公的妹妹穿的比我還像新娘司蔬。我一直安慰自己,他們只是感情好姨蝴,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評論 6 398
  • 文/花漫 我一把揭開白布俊啼。 她就那樣靜靜地躺著,像睡著了一般左医。 火紅的嫁衣襯著肌膚如雪授帕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,807評論 1 314
  • 那天浮梢,我揣著相機(jī)與錄音跛十,去河邊找鬼。 笑死秕硝,一個(gè)胖子當(dāng)著我的面吹牛芥映,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 41,235評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼奈偏,長吁一口氣:“原來是場噩夢啊……” “哼坞嘀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惊来,我...
    開封第一講書人閱讀 40,189評論 0 277
  • 序言:老撾萬榮一對情侶失蹤丽涩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后裁蚁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矢渊,經(jīng)...
    沈念sama閱讀 46,712評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評論 3 343
  • 正文 我和宋清朗相戀三年厘擂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昆淡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,926評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡刽严,死狀恐怖昂灵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情舞萄,我是刑警寧澤眨补,帶...
    沈念sama閱讀 36,580評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站倒脓,受9級特大地震影響撑螺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜崎弃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評論 3 336
  • 文/蒙蒙 一甘晤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧饲做,春花似錦线婚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至泪姨,卻和暖如春游沿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肮砾。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評論 1 274
  • 我被黑心中介騙來泰國打工诀黍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人唇敞。 一個(gè)月前我還...
    沈念sama閱讀 49,368評論 3 379
  • 正文 我出身青樓蔗草,卻偏偏與公主長得像咒彤,于是被迫代替她去往敵國和親疆柔。 傳聞我的和親對象是個(gè)殘疾皇子咒精,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評論 2 361

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