EventBus使用和源碼詳解

目錄

1. 架構圖

2. 使用

3. 源碼解析

3.1 @Subscribe註解

3.1.1 threadMode: 配置消息接收是在哪個線程

3.1.2 sticky : 粘性事件

3.1.3 priority :  接收事件的優先級

3.2 註解解析

3.2.1 註解類上的元註解

3.2.2  collectSubscribers收集訂閱類和訂閱的方法信息

3.2.3 生成MyEventBusIndex類

3.3 註冊流程解析

3.3.1 註冊流程

3.3.2 查找訂閱方法findSubscriberMethods()

3.3.3 存儲訂閱類信息subscribe()

3.3.4 取消訂閱

3.4 消息發送和接收解析

3.4.1 postSticky粘性消息

3.4.2 post普通消息

4. 總結


1. 架構圖

從官網的架構圖可以看出來,EventBus可以將發佈者和訂閱者解偶,這就是EventBus最大的方便之處。

2. 使用

請參考我的另外一篇文章:https://blog.csdn.net/fwt336/article/details/103133850

3. 源碼解析

3.1 @Subscribe註解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;

    /**
     * If true, delivers the most recent sticky event (posted with
     * {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
     */
    boolean sticky() default false;

    /** Subscriber priority to influence the order of event delivery.
     * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
     * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
     * delivery among subscribers with different {@link ThreadMode}s! */
    int priority() default 0;
}

從Subscribe註解中的元註解可以看出來,我們的Subscribe是運行時註解,只能在運行時進行解析,也只能註冊Method方法。

裏面有三個參數可以進行配置:threadMode,sticky, priority。

3.1.1 threadMode: 配置消息接收是在哪個線程

有5種線程設置方式:

POSTING : 消息的接收與消息發送在同一個線程處理

MAIN : 消息在UI線程處理,但是如果發送線程是在UI線程,消息將會直接被調用處理,將阻塞調用線程。

MAIN_ORDERED : 消息在主線程處理,但是跟MAIN不一樣的是,消息將會加入到隊列中進行處理,不回堵塞調用線程。

BACKGROUND : 消息在後臺線程處理,如果發送線程不是UI線程,則將會直接在發送線程處理消息。如果發送線程是UI線程,那麼將使用一個後臺線程,按照事件順序處理。

ASYNC :消息將在單獨的線程中調用,如果消息處理很耗時,可以採用這種方法,最終是EventBus使用線程池來處理消息。

3.1.2 sticky : 粘性事件

默認爲false,如果設置爲true,其作用與粘性廣播的使用類似。也就是我們的粘性事件可以在事件註冊前發送,當註冊事件,並設置接收粘性事件後,將會接收到粘性事件。如果在註冊之前發送了兩個粘性事件,則只會接收到最後一個事件。

調用時,需用使用postSticky方法:

EventBus.getDefault().postSticky(new EventObject());

接收方法添加sticky = true即可,例如:

@Subscribe(threadMode = ThreadMode.Main, sticky = true)

stickyEventReceiver() {}

3.1.3 priority :  接收事件的優先級

在註冊時將會用到這個參數,根據優先級加入到訂閱者列表中。

3.2 註解解析

3.2.1 註解類上的元註解

先看看註解處理器上的註解修飾

@SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe")
@SupportedOptions(value = {"eventBusIndex", "verbose"})
public class EventBusAnnotationProcessor extends AbstractProcessor {}
SupportedAnnotationTypes : 指定處理器支持的處理類型
SupportedOptions : 用來表示所支持的附加選項

在運行apt命令行工具的時候,可以通過-A來傳遞額外的參數給註解處理器,如-Averbose=true。當通過 supportedOptions方法聲明瞭所能識別的附加選項之後,註解處理器就可以在運行時刻通過AnnotationProcessorEnvironment的getOptions方法獲取到選項的實際值。

public static final String OPTION_EVENT_BUS_INDEX = "eventBusIndex";
    public static final String OPTION_VERBOSE = "verbose";

@Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
            Messager messager = processingEnv.getMessager();
            String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX);
            if (index == null) {
                messager.printMessage(Diagnostic.Kind.ERROR, "No option " + OPTION_EVENT_BUS_INDEX +
                        " passed to annotation processor");
                return false;
            }
            verbose = Boolean.parseBoolean(processingEnv.getOptions().get(OPTION_VERBOSE));
            int lastPeriod = index.lastIndexOf('.');
            String indexPackage = lastPeriod != -1 ? index.substring(0, lastPeriod) : null;

            round++;
            if (verbose) {
                messager.printMessage(Diagnostic.Kind.NOTE, "Processing round " + round + ", new annotations: " +
                        !annotations.isEmpty() + ", processingOver: " + env.processingOver());
            }
        return true;
    }
eventBusIndex選項值是註解器生成的一個類的路徑,是必須要傳遞的一個值,它是在build.gradle中進行傳遞的:
android {

    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [eventBusIndex: 'org.greenrobot.eventbusperf.MyEventBusIndex']
            }
        }
    }
}

後面我們將會使用到這個類。

而verbose則是一個控制調試信息打印的變量,可傳可不傳。

3.2.2  collectSubscribers收集訂閱類和訂閱的方法信息

而我們的主要工作在下面三個方法上:

@Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
        Messager messager = processingEnv.getMessager();
        try {
            // ...
            collectSubscribers(annotations, env, messager); // 1.收集註解類和方法
            checkForSubscribersToSkip(messager, indexPackage); // 2.過濾事件

            if (!methodsByClass.isEmpty()) {
                createInfoIndexFile(index); // 3.生成MyEventBusIndex類
            } else {
                messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found");
            }
            // ...
        } catch (RuntimeException e) {
        }
        return true;
    }

看下collectSubscribers源碼:

private void collectSubscribers(Set<? extends TypeElement> annotations, RoundEnvironment env, Messager messager) {
        for (TypeElement annotation : annotations) {
            Set<? extends Element> elements = env.getElementsAnnotatedWith(annotation);
            for (Element element : elements) {
                if (element instanceof ExecutableElement) {
                    ExecutableElement method = (ExecutableElement) element;
                    if (checkHasNoErrors(method, messager)) {
                        TypeElement classElement = (TypeElement) method.getEnclosingElement();
                        methodsByClass.putElement(classElement, method);
                    }
                } else {
                    messager.printMessage(Diagnostic.Kind.ERROR, "@Subscribe is only valid for methods", element);
                }
            }
        }
    }

它會遍歷每一個Subscriber標誌信息,將標註的類和標註方法對應起來,存儲到methodByClass裏,方便後面使用。

同時,它還會檢查方法是否被static修飾了,是不是被public修飾的,是否只有一個參數,也就是我們的事件參數只能是一個。

private boolean checkHasNoErrors(ExecutableElement element, Messager messager) {
        if (element.getModifiers().contains(Modifier.STATIC)) { // 檢查是否有static修飾
            messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must not be static", element);
            return false;
        }

        if (!element.getModifiers().contains(Modifier.PUBLIC)) { // 檢查是不是public修飾的
            messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must be public", element);
            return false;
        }

        List<? extends VariableElement> parameters = ((ExecutableElement) element).getParameters();
        if (parameters.size() != 1) { // 檢查參數是否有且只有一個
            messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must have exactly 1 parameter", element);
            return false;
        }
        return true;
    }

而我們收集到的數據methodsByClass將在checkForSubscribersToSkip方法和生成MyEventBusIndex時的writeIndexLines()方法中使用到。

checkForSubscribersToSkip流程:

private void checkForSubscribersToSkip(Messager messager, String myPackage) {
        for (TypeElement skipCandidate : methodsByClass.keySet()) {
            TypeElement subscriberClass = skipCandidate;
            while (subscriberClass != null) {
                if (!isVisible(myPackage, subscriberClass)) {  // 判斷方法是否可見,public修飾或在同一個包內
                    boolean added = classesToSkip.add(skipCandidate);
                    break;
                }
                List<ExecutableElement> methods = methodsByClass.get(subscriberClass);
                if (methods != null) {
                    for (ExecutableElement method : methods) {
                        String skipReason = null;
                        VariableElement param = method.getParameters().get(0);
                        TypeMirror typeMirror = getParamTypeMirror(param, messager);
                        if (!(typeMirror instanceof DeclaredType) ||
                                !(((DeclaredType) typeMirror).asElement() instanceof TypeElement)) {
                            skipReason = "event type cannot be processed";
                        }
                        if (skipReason == null) {
                            TypeElement eventTypeElement = (TypeElement) ((DeclaredType) typeMirror).asElement();
                            if (!isVisible(myPackage, eventTypeElement)) {
                                skipReason = "event type is not public";
                            }
                        }
                        if (skipReason != null) {
                            boolean added = classesToSkip.add(skipCandidate);
                            break;
                        }
                    }
                }
// 遍歷父類中的方法
                subscriberClass = getSuperclass(subscriberClass);
            }
        }
    }

a.首先會遍歷所有標了Subscribe註解的類;

b.判斷類是否可見,即是否有public修飾,或是否與MyEventBusIndex.java在同一個包內,或沒有修飾符。不可見則放入classToSkip需要過濾的容器中;

private boolean isVisible(String myPackage, TypeElement typeElement) {
        Set<Modifier> modifiers = typeElement.getModifiers();
        boolean visible;
        if (modifiers.contains(Modifier.PUBLIC)) {
            visible = true;
        } else if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.PROTECTED)) {
            visible = false;
        } else {
            String subscriberPackage = getPackageElement(typeElement).getQualifiedName().toString();
            if (myPackage == null) {
                visible = subscriberPackage.length() == 0;
            } else {
                visible = myPackage.equals(subscriberPackage);
            }
        }
        return visible;
    }

c.遍歷Subscribe標註的類對應的所有註解方法;

d.判斷Class是否是類或接口DeclaredType,不是則放入classToSkip需要過濾的容器中;

e.遍歷父類,重複b,c,d方法

3.2.3 生成MyEventBusIndex類

配置生成EventBusIndex類使註解生成類生效

主要是看下writeIndexLines方法,其他生成的代碼都是固定的:

private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException {
        for (TypeElement subscriberTypeElement : methodsByClass.keySet()) {
            if (classesToSkip.contains(subscriberTypeElement)) {
                continue;
            }

            String subscriberClass = getClassString(subscriberTypeElement, myPackage);
            if (isVisible(myPackage, subscriberTypeElement)) {
                writeLine(writer, 2,
                        "putIndex(new SimpleSubscriberInfo(" + subscriberClass + ".class,",
                        "true,", "new SubscriberMethodInfo[] {");
                List<ExecutableElement> methods = methodsByClass.get(subscriberTypeElement);
                writeCreateSubscriberMethods(writer, methods, "new SubscriberMethodInfo", myPackage);
                writer.write("        }));\n\n");
            } else {
                writer.write("        // Subscriber not visible to index: " + subscriberClass + "\n");
            }
        }
    }

也就是遍歷我們收集到的帶有@Subscribe註解的類,過濾出有效的類,再將我們的註冊類名和註解參數封裝起來,放入到SUBSCRIBER_INDEX這個map中,對外提供查找方法getSubscriberInfo()。

看下生成的這個類長什麼樣子:

package org.greenrobot.eventbusperf;

import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberMethodInfo;
import org.greenrobot.eventbus.meta.SubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberInfoIndex;

import org.greenrobot.eventbus.ThreadMode;

import java.util.HashMap;
import java.util.Map;

/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;

    static {
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();

        putIndex(new SimpleSubscriberInfo(TestRunnerActivity.class, true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onTestEvent", TestEvent.class, ThreadMode.MAIN),
        }));

        putIndex(new SimpleSubscriberInfo(TestActivity.class, true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onDemoEvent", TestEvent.class, ThreadMode.MAIN_ORDERED, 0, true),
        }));

    }

    private static void putIndex(SubscriberInfo info) {
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }

    @Override
        public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }
}

3.3 註冊流程解析

3.3.1 註冊流程

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

大致流程是:通過註冊方法所在的類名,查找到所有註冊類的訂閱方法,然後在遍歷每個訂閱方法,將事件類型eventType跟訂閱器Subscription(內部封裝了訂閱類所需的所有參數)存入到subscriptionsByEventType中,而subscriptionsByEventType在進行消息分發查找時將會用到Subscription數據。

3.3.2 查找訂閱方法findSubscriberMethods()

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        if (ignoreGeneratedIndex) {
            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;
        }
    }

從源碼可以發現查找方法名有兩種方式,一種時反射,另一種是通過獲取註解處理器生成的類MyEventBusIndex獲取,而默認ignoreGeneratedIndex是false。

反射查找所有方法則是通過獲取註冊類的所有方法,找到可見的且標註了@Subscribe註解的方法,然後封裝成SubscriberMethod類返回一個SubscriberMethod的list。

通過註解類查找定製類型的所有方法

註解處理器生成類的注入:

/** Adds an index generated by EventBus' annotation preprocessor. */
    public EventBusBuilder addIndex(SubscriberInfoIndex index) {
        if (subscriberInfoIndexes == null) {
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }

待用EventBusBuilder的addInex()方法後,這樣,我們的註解處理器的作用才真正達到了。

但是,當沒有配置註解器時,將強制使用反射方式進行處理。

那麼問題來了,你在使用EventBus時配置了EventBusIndex類嗎?

配置生成EventBusIndex類使註解生成類生效

3.3.3 存儲訂閱類信息subscribe()

我們將subscribe()方法分爲三個部分來看。

a.存儲訂閱者信息

將訂閱事件和訂閱方法封裝到Subscription中,然後以列表的形式存儲在subscriptionsByEventType中,事件類型爲key。而訂閱事件發送的時候,也會從subscriptionsByEventType map中,將事件對應的subscriber訂閱器信息取出來,然後進行消息事件的反射。

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

        // ...處理事件優先級

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

        //...處理粘性事件
    }

b. 處理消息事件優先級

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    // ... 
    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;
            }
        }
    // ...
}

每個方法插入列表的時候,將根據優先級插入,然後將列表保存在subscriptionsByEventType中。

c. 處理粘性消息

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        // ...
        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();
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }
eventInheritance默認爲true,所以會遍歷整個stickyEvents,然後將stickyEvents中的消息事件分發出去:
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        if (stickyEvent != null) {
            postToSubscription(newSubscription, stickyEvent, isMainThread()); // 分發給對應的poster處理
        }
    }

3.3.4 取消訂閱

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中對應的事件的註冊類移除即可。

3.4 消息發送和接收解析

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

通過源碼我們可以發現,postSticky最終還是調用了post方法,只是會多一步將event加入stickyEvents中存儲起來,當註冊的時候會判斷是否有對應可能的粘性事件。

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

在post有會保存當前線程的一個狀態,即PostingThreadState。但是查了下沒有set方法,只有get,原來當沒有有效值時,內部創建了一個默認的PostingThreadState。

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };

當事件消息過來後,首先會通過ThreadLocal找到當前的線程PostingThreadState狀態,獲取到PostingThreadState中的隊列,然後加入到隊列中,如果此時線程正在分發消息,則退出,最後加入到消息將由正在分發消息的線程分發。

下面看下具體到消息分發:postSingleEvent(eventQueue.remove(0), postingState);

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方法繼續分發事件。

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

最終通過事件類名從subscriptionsByEventType集合中找到對應的所有訂閱類,而我們在註冊的時候,將事件類名和訂閱類存入到類subscriptionsByEventType中。

找到所有的訂閱類subscriptions後,遍歷所有訂閱類,然後通過postToSubscription方法進行具體的消息分發處理。

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

最終會通過初始化時的分發器,根據threadMode類型進行消息的處理。如果是posting線程則直接調用invokeSubscriber處理,如果是後臺線程或者異步線程,則都是調用EventBus的線程池進行處理消息隊列中的消息,而UI線程則是通過handler進行處理。

看下mainPoster的代碼就知道了,確實是通過new HandlerPoster處理的,而HandlerPoster繼承了Handler,並實現了Poster接口:

public interface MainThreadSupport {

    boolean isMainThread();

    Poster createPoster(EventBus eventBus);

    class AndroidHandlerMainThreadSupport implements MainThreadSupport {

        private final Looper looper;

        public AndroidHandlerMainThreadSupport(Looper looper) {
            this.looper = looper;
        }

        @Override
        public boolean isMainThread() {
            return looper == Looper.myLooper();
        }

        @Override
        public Poster createPoster(EventBus eventBus) {
            return new HandlerPoster(eventBus, looper, 10);
        }
    }
}

重點來了,最後所有消息處理都是通過反射實現的:

void invokeSubscriber(PendingPost pendingPost) {
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        PendingPost.releasePendingPost(pendingPost);
        if (subscription.active) {
            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);
        }
    }

終於看到了久違的invoke方法!

4. 總結

EventBus可以通過註解和反射兩種方式來獲取到訂閱者的相關信息,然後通過UI線程或內部的線程池處理髮送的消息事件,最終是通過反射實現訂閱者方法的調用,有訂閱者處理消息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章