EventBus源代码全解析

EventBus 3.2.0 源码阅读

名词定义

  1. 订阅者:某一个类,通过register()方法完成注册.
  2. 订阅方法:某一个方法,通过@Subscribe注解,是订阅事件被处理,消费的地方.
  3. 订阅事件类型:订阅方法的入参,是订阅方法希望接受的事件类型.

@Subscribe

@Subscribe注解可以指定三个值,分别是ThreadMode,指定订阅方法在什么线程下处理订阅事件,默认为POSTRING;sticky,指定接受的订阅事件是否是粘性事件,默认为false;priority,指定订阅方法的优先级,默认为0.
EventBus Subscribe

ThreadMode

  1. POSTING(默认值)
    订阅方法会在发布线程(Posting Thread)下完成事件的处理,即在发布线程下直接执行.
    由于发布线程直接执行订阅方法,是同步的过程.因此,后续的事件发布,需要等待当前订阅方法的处理完成,才能继续进行.而发布线程可能是 UI 线程,因此,声明为POSTRING的订阅方法不应该处理耗时任务,否则,会影响 UI 线程其他事件的处理以及后续订阅方法接收到订阅事件的速度.
  2. MAIN,MAIN_ORDERED(Android Only)
    订阅方法会在UI 线程下完成事件的处理.
    对于MAIN,如果发布线程是 UI 线程,则直接执行;否则,通过 Handler 处理.(类似runOnUiThread())
    如果是MAIN_ORDERED,则不管发布线程是否是 UI 线程,都通过 Handler 处理.
    同样,不能处理耗时任务.
  3. BACKGROUND
    订阅方法会在非 UI 线程下完成事件的处理.
    如果发布线程不是 UI 线程,则直接执行;否则,创建线程执行(如果上一个任务还在执行,后面添加的任务会和上一个任务在同一个线程下执行).
    同样,不能处理耗时任务,避免后续订阅方法接收订阅事件.
    非 Android 下,不区分 UI 线程和非 UI 线程.统一为BACKGROUND.
  4. ASYNC
    订阅方法会在独立线程下完成事件的处理.即,不管发布线程是否是 UI 线程,都会创建新线程执行.
    可执行耗时任务.

EventBus 源码解析

注册流程

注册流程主要完成订阅方法,订阅者以及订阅事件类型之间的映射关系,并处理粘性订阅事件.
注册流程

  1. 使用者通过register()发起注册,在register()中,首先通过SubscriberMethodFinder获取该订阅者的所有订阅方法.

    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
    
  2. 通过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);
            }
        }
    }
    
    private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        if (stickyEvent != null) {
            // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
            // --> Strange corner case, which we don't take care of here.
            postToSubscription(newSubscription, stickyEvent, isMainThread());
        }
    }
    

注销流程

注销流程主要通过注册流程中创建的映射关系,获取到订阅事件类型与订阅者之间的映射关系,从某一订阅事件类型下的所有订阅中取消待注销的订阅者的订阅.
注销流程

  1. 使用者通过unregister()发起注销,在unregister()中,首先通过typesBySubscriber获取该订阅者的所有订阅事件类型.

    /** Unregisters the given subscriber from all event classes. */
    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());
        }
    }
    
  2. 从获取到的订阅事件类型中找到待注销订阅者的订阅方法,并删除

    /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
    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--;
                }
            }
        }
    }
    

发布流程

发布流程主要工作是,根据每一个订阅方法的ThreadMode,选择不同的,执行订阅方法的途径.
发布流程

发布流程主要有两种类型的事件.对于粘性事件,需要将事件保存,供后续使用;对于普通事件,则不需要保存.

  1. 粘性事件,需要先将粘性事件保存下来.之后走普通事件的发布流程.

    /**
     * Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky
     * event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}.
     */
    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);
    }
    
  2. post()方法主要完成一些条件的初始化,和解决循环发布的问题.
    PostingThreadState.eventQueue主要用来解决在发布线程下直接执行订阅方法,而该订阅方法也会发布订阅事件导致的循环嵌套问题.
    PostingThreadState.isPosting主要用来,在取消事件分发过程中,判断当前线程是否是发布线程.
    PostingThreadState.isMainThread主要用来判断订阅方法是否可以直接执行

    /** Posts the given event to the event bus. */
    public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();  //  ThreadLocal变量
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);
    
        if (!postingState.isPosting) {  //  是否处于发布状态,主要用来区分取消事件的操作是否是在Posting线程下执行,以便取消事件传递时使用.
            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;
            }
        }
    }
    
    private boolean isMainThread() {
        return mainThreadSupport == null || mainThreadSupport.isMainThread();
    }
    
  3. 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));
            }
        }
    }
    
    /** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */
    private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {    //  将订阅事件的所有父类即接口添加到缓存中
        synchronized (eventTypesCache) {
            List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
            if (eventTypes == null) {
                eventTypes = new ArrayList<>();
                Class<?> clazz = eventClass;
                while (clazz != null) {
                    eventTypes.add(clazz);
                    addInterfaces(eventTypes, clazz.getInterfaces());
                    clazz = clazz.getSuperclass();
                }
                eventTypesCache.put(eventClass, eventTypes);
            }
            return eventTypes;
        }
    }
    
    /** Recurses through super interfaces. */
    static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {
        for (Class<?> interfaceClass : interfaces) {
            if (!eventTypes.contains(interfaceClass)) { //  去重
                eventTypes.add(interfaceClass);
                addInterfaces(eventTypes, interfaceClass.getInterfaces());
            }
        }
    }
    
  4. postSingleEventForEventType()主要按照优先级顺序,将订阅事件发布到各个订阅方法.
    PostingThreadState.event主要用来,在取消后续事件发布的过程中,判断取消的事件是否是正在发布的事件.
    PostingThreadState.subscription主要用来,在取消后续事件发布的过程中,判断发起取消事件发布的订阅方法是否是POSTRING.
    PostingThreadState.canceled主要用来,退出循环,中断事件发布.

    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;
    }
    
  5. postToSubscription()主要判断能否在当前线程先直接执行订阅方法.如果可以,则直接执行;否则,通过Poster完成相应处理.

    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:    //  在非Android下,isMainThread==false,mainThreadPoster==null,所以,POSTING,MAIN,MAIN_ORDERED,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);
        }
    }
    
    /**
     * Invokes the subscriber if the subscriptions is still active. Skipping subscriptions prevents race conditions
     * between {@link #unregister(Object)} and event delivery. Otherwise the event might be delivered after the
     * subscriber unregistered. This is particularly important for main thread delivery and registrations bound to the
     * live cycle of an Activity or Fragment.
     */
    void invokeSubscriber(PendingPost pendingPost) {    //  Poster调用此方法
        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);
        }
    }
    

取消订阅

  1. 取消普通的订阅事件

    事件能够取消需要满足的条件:

    1. cancelEventDelivery()应该在发布线程中执行.
      订阅方法对订阅事件的处理存在同步(在发布线程下直接执行)和异步两种情况.对于异步处理,由于处于不同的线程,没办法干涉到其他事件的处理,因此,不能完成取消事件传递的操作.
      因此,取消事件传递就需要判断当前的线程是否是发布线程!postingState.isPosting.
      (因为发布线程下直接执行订阅方法,发布线程一定处于发布状态;而订阅方法如果是通过异步执行的,那么他所在的线程一定不在发布状态.).
    2. 取消的事件类型应该是当前正在发布的类型.
      取消事件发布是通过中断postSingleEventForEventType()中的事件发布循环实现的,而这个循环是针对当前正在发布的事件进行的,所以,无法中断其他的事件发布.即,其他事件的发布还未开始,不能中断.
    3. cancelEventDelivery()应该在POSTING的订阅方法中执行.
      声明为POSTING以外的ThreadMode,总会有通过Poster执行的时候,由于cancelEventDelivery()在不符合条件时,会直接抛出异常,导致程序崩溃.所以,要求为POSTING,避免崩溃.

    这些条件的作用,主要是防止错误置位postingState.canceled,导致在post()时抛出异常.

    /**
     * Called from a subscriber's event handling method, further event delivery will be canceled. Subsequent
     * subscribers
     * won't receive the event. Events are usually canceled by higher priority subscribers (see
     * {@link Subscribe#priority()}). Canceling is restricted to event handling methods running in posting thread
     * {@link ThreadMode#POSTING}.
     */
    public void cancelEventDelivery(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        if (!postingState.isPosting) {  //  判断是否是在发布线程下,只有订阅方法在发布线程下执行的时候,才能取消事件发布
            throw new EventBusException(
                    "This method may only be called from inside event handling methods on the posting thread");
        } else if (event == null) {
            throw new EventBusException("Event may not be null");
        } else if (postingState.event != event) {   //  判断取消的事件是否是正在发布的事件,只能取消当前正在发布的事件
            throw new EventBusException("Only the currently handled event may be aborted");
        } else if (postingState.subscription.subscriberMethod.threadMode != ThreadMode.POSTING) {   //  判断订阅方法是否是POSTING,只有是POSTING的订阅方法,才能取消事件发布
            throw new EventBusException(" event handlers may only abort the incoming event");
        }
    
        postingState.canceled = true;
    }
    
  2. 取消粘性事件

    /**
     * Remove and gets the recent sticky event for the given event type.
     *
     * @see #postSticky(Object)
     */
    public <T> T removeStickyEvent(Class<T> eventType) {    //  通过订阅事件类型去除粘性事件
        synchronized (stickyEvents) {
            return eventType.cast(stickyEvents.remove(eventType));
        }
    }
    
    /**
     * Removes the sticky event if it equals to the given event.
     *
     * @return true if the events matched and the sticky event was removed.
     */
    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;
            }
        }
    }
    
    /**
     * Removes all sticky events.
     */
    public void removeAllStickyEvents() {
        synchronized (stickyEvents) {
            stickyEvents.clear();
        }
    }
    

SubscriberMethodFinder

SubscriberMethodFinder查找订阅方法流程

  1. 首先,SubscriberMethodFinder通过METHOD_CACHE尝试从缓存中获取数据.如果缓存命中,这表明该类已被解析过,则直接返回缓存值;否则,判断是否在初始化时指定设置ignoreGeneratedIndex=true,如果有,则通过反射的方式获取订阅方法;否则,使用索引获取订阅方法.最后,将订阅方法写入缓存中,并返回给 EventBus.

    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;
        }
    }
    
  2. 方法的获取借助FindState类进行.SubscriberMethodFinder使用一个大小为 4 的FindState的缓存池.使用时,通过prepareFindState方法,从池中获取一个FindState.如果获取不到,则临时创建一个使用.
    使用时,将要解析的类写入到FindState,完成初始化.

        private FindState prepareFindState() {
            synchronized (FIND_STATE_POOL) {
                for (int i = 0; i < POOL_SIZE; i++) {
                    FindState state = FIND_STATE_POOL[i];
                    if (state != null) {
                        FIND_STATE_POOL[i] = null;
                        return state;
                    }
                }
            }
            return new FindState();
        }
    
    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findUsingReflectionInSingleClass(findState);
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }
    
  3. 通过反射的方式获取订阅方法中,首先通过getDeclaredMethods()获取类中声明的方法(不包含继承的方法).如果过程中出现异常,则改为使用getMethods()获取public方法,包括继承自父类/父接口的方法.如果使用getDeclaredMethods()获取,则递归完成其父类的订阅方法获取.

    订阅方法需要满足的条件:

    1. abstract,static,bridge,synthetic
    2. public
    3. 使用@Subscribe注解
    4. 参数有且只有一个
    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findUsingReflectionInSingleClass(findState);
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }
    
    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
            try {
                methods = findState.clazz.getMethods();
            } catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad...
                String msg = "Could not inspect methods of " + findState.clazz.getName();
                if (ignoreGeneratedIndex) {
                    msg += ". Please consider using EventBus annotation processor to avoid reflection.";
                } else {
                    msg += ". Please make this class visible to EventBus annotation processor to avoid reflection.";
                }
                throw new EventBusException(msg, error);
            }
            findState.skipSuperClasses = true;  //  通过getMethods()获取的方法已经包含了父类的方法,不需要再递归了.
        }
        for (Method method : methods) {
            int modifiers = method.getModifiers();
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {    //  非abstract,static,bridge,synthetic,是public
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {   //  订阅的方法参数有且只能有一个
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {  //  使用@Subscribe注解
                        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");
            }
        }
    }
    
  4. 通过索引的方式,直接从索引中获取订阅的方法;如果索引不存在,则使用反射的方式获取.

    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);
    }
    
    private SubscriberInfo getSubscriberInfo(FindState findState) {
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {    //  第一次 findState.subscriberInfo == null,此处是通过findState.subscriberInfo,在递归的过程中,来获取父类的 subscriberInfo 的逻辑
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }
        if (subscriberInfoIndexes != null) {    //  此处是首次进入,获取注册类自身的 subscriberInfo的逻辑
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }
    

FindState

方法去重,判断订阅的方法是否存在重复的情况.

boolean checkAdd(Method method, Class<?> eventType) {
    // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
    // Usually a subscriber doesn't have methods listening to the same event type.
    Object existing = anyMethodByEventType.put(eventType, method);
    if (existing == null) { //  订阅的事件类型在类中第一次出现
        return true;
    } else {    //  订阅的事件类型在类中多次出现
        if (existing instanceof Method) {   //  对同一事件类型的第二次出现判断方法是否相同(签名相同),相同的,抛出异常
            if (!checkAddWithMethodSignature((Method) existing, eventType)) {   //  此处是将existing放入subscriberClassByMethodKey中,给method去判断的
                // Paranoia check
                throw new IllegalStateException();
            }
            // Put any non-Method object to "consume" the existing Method
            anyMethodByEventType.put(eventType, this);  //  对同一事件类型的第三次及以后的出现,不再进行该if判断
        }
        return checkAddWithMethodSignature(method, eventType);
    }
}

private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
    methodKeyBuilder.setLength(0);
    methodKeyBuilder.append(method.getName());
    methodKeyBuilder.append('>').append(eventType.getName());

    String methodKey = methodKeyBuilder.toString();
    Class<?> methodClass = method.getDeclaringClass();
    Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
    if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {   //  方法不相同或相同方法所在类(methodClass)是已添加方法所在类(methodClassOld)的子类
        // Only add if not already found in a sub class
        return true;
    } else {
        // Revert the put, old class is further down the class hierarchy
        subscriberClassByMethodKey.put(methodKey, methodClassOld);
        return false;
    }
}

void moveToSuperclass() {
    if (skipSuperClasses) {
        clazz = null;
    } else {
        clazz = clazz.getSuperclass();
        String clazzName = clazz.getName();
        // Skip system classes, this degrades performance.
        // Also we might avoid some ClassNotFoundException (see FAQ for background).
        if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") ||
                clazzName.startsWith("android.") || clazzName.startsWith("androidx.")) {
            clazz = null;
        }
    }
}

Poster

  1. AsyncPoster

    对应ASYNC,使用线程池执行.

    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);
    }
    
  2. BackgroundPoster

    对应BACKGROUND,使用线程池执行.与ASYNC不同的是,BACKGROUND中,后一个任务如果在前一个任务执行的过程中加入队列,则会由上一个任务所在线程继续执行.

    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) {  //  使得BACKGROUND的订阅方法尽可能在同一线程中执行
                    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;
        }
    }
    
  3. HandlerPoster

    对应MAINMAIN_ORDERED,Handler执行.与BackgroundPoster类似,HandlerPoster在一次处理中会尽可能多的完成订阅事件的处理.但是,作为 UI 线程,需要处理其他的事情.因此,订阅事件的处理不能无限制的执行.因此,HandlerPoster对订阅事件的连续处理时长,做了 10ms 的限制.当连续处理时间超过 10ms 时,则中断下一个事件的处理,在下一次 UI 线程空闲的时候继续处理.

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }
    
    @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) { //  超过10ms,则中断处理,在下一次空闲时,继续
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
    

PendingPost

待处理的发布事件,作为Poster处理事件发布时的数据载体

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

PendingPostQueue

待处理的发布事件的队列,每个Poster持有一个

synchronized void enqueue(PendingPost pendingPost) {
    if (pendingPost == null) {
        throw new NullPointerException("null cannot be enqueued");
    }
    if (tail != null) {
        tail.next = pendingPost;
        tail = pendingPost;
    } else if (head == null) {
        head = tail = pendingPost;
    } else {
        throw new IllegalStateException("Head present, but no tail");
    }
    notifyAll();
}

synchronized PendingPost poll() {
    PendingPost pendingPost = head;
    if (head != null) {
        head = head.next;
        if (head == null) {
            tail = null;
        }
    }
    return pendingPost;
}

synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
    if (head == null) {
        wait(maxMillisToWait);
    }
    return poll();
}

EventBusBuilder

对 EventBus 进行定制的一些参数.

  1. logSubscriberExceptions(boolean)
    默认为true.
    在通过反射执行订阅方法时,如果抛出InvocationTargetException,logSubscriberExceptions控制是否打印日志.
  2. logNoSubscriberMessages(boolean)
    默认为true.
    控制在处理订阅事件分发时,如果某一个事件类型没有找到订阅者,是否打印日志.
  3. sendSubscriberExceptionEvent(boolean)
    默认为true.
    在通过反射执行订阅方法时,如果抛出InvocationTargetException,sendSubscriberExceptionEvent控制是否发布SubscriberExceptionEvent事件(如果logSubscriberExceptionstrue,会多打印一些日志).
  4. sendNoSubscriberEvent(boolean)
    默认为true.
    控制在处理订阅事件分发时,如果某一个事件类型没有找到订阅者,是否发布NoSubscriberEvent(该事件是测试用的).
  5. throwSubscriberException(boolean)
    默认为false.
    在通过反射执行订阅方法时,如果抛出InvocationTargetException,throwSubscriberException控制是否抛出EventBusException.
  6. eventInheritance(boolean)
    默认为true.
    控制订阅事件类型是否要考虑超类的情况(即订阅方法接受的事件类型是发布事件类型的超类).关闭提升可 20%或更多的性能.
  7. executorService(ExecutorService)
    默认为newCachedThreadPool.
    AsyncPosterBackgroundPoster执行任务的线程池.
  8. skipMethodVerificationFor(Class<?>)
    使用ArrayList存储,默认为空.
    为以onEvent开头的方法进行方法名称验证,以避免输入错误;使用此方法,您可以从此检查中排除订户类别.还禁用对方法修饰符(公共,非静态或抽象)的检查.(代码中没有用到)
  9. ignoreGeneratedIndex(boolean)
    默认为false.
    控制在SubscriberMethodFinder查找订阅方法时,是否忽略索引,强制使用反射.
  10. strictMethodVerification(boolean)
    默认为false.
    控制在SubscriberMethodFinder查找订阅方法时,如果@Subscribe注解的方法不符合条件,是否抛出EventBusException.
  11. addIndex(SubscriberInfoIndex)
    使用ArrayList存储,默认为空.
    添加通过EventBus annotation preprocessor生成的索引.
  12. logger(Logger)
    默认为android.util.Log.
    自定义日志程序.
  13. installDefaultEventBus()
    EventBus.getDefault()返回的是使用当前 builder 创建的 EventBus(在使用 default EventBus 之前,必须且仅调用一次).

代码中,并没有对EventBusException进行 catch.因此,抛出异常会导致应用崩溃.

其他的问题

  1. 如何判断是否是 Android?
    EventBusBuildergetMainThreadSupport()方法中,会尝试获取MainThreadSupport(UI 线程的Poster就是由它创建的).该方法会查找是否有android.util.Log这个类.如果有,在尝试通过Looper.getMainLooper()获取MainLooper,如果获取成功,则认为是 Android,并创建MainThreadSupport.

    //  EventBusBuilder
    MainThreadSupport getMainThreadSupport() {
        if (mainThreadSupport != null) {
            return mainThreadSupport;
        } else if (AndroidLogger.isAndroidLogAvailable()) {
            Object looperOrNull = getAndroidMainLooperOrNull();
            return looperOrNull == null ? null : new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
        } else {
            return null;
        }
    }
    
    //  AndroidLogger
    static {
        boolean android = false;
        try {
            android = Class.forName("android.util.Log") != null;
        } catch (ClassNotFoundException e) {
            // OK
        }
        ANDROID_LOG_AVAILABLE = android;
    }
    
    public static boolean isAndroidLogAvailable() {
        return ANDROID_LOG_AVAILABLE;
    }
    
  2. 如何判断是否是 UI 线程?
    通过判断当前线程的Looper是否是MainLooper完成.

    //  AndroidHandlerMainThreadSupport
    public AndroidHandlerMainThreadSupport(Looper looper) { //  EventBusBuilder中初始化时,使用MainLooper初始化
        this.looper = looper;
    }
    
    public boolean isMainThread() {
        return looper == Looper.myLooper(); //  Return the Looper object associated with the current thread. Returns null if the calling thread is not associated with a Looper.
    }
    
  3. 有关在订阅方法中执行post()可能导致的问题

    /** Posts the given event to the event bus. */
    public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();  //  ThreadLocal变量
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);
    
        if (!postingState.isPosting) {  //  是否处于发布状态,主要用来区分取消事件的操作是否是在Posting线程下执行,以便取消事件传递时使用.
            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()方法,由于是直接执行,当前线程处于发布状态,因此,订阅方法中调用的post()方法并不会立刻发布,而是加入队列中,等到当前事件发布完成,才会发布.
    当在非发布线程中执行的订阅方法内,调用post()方法,由于处于不同线程,因此,当前线程是非发布状态,订阅方法中调用的post()方法会立刻发布事件,这样一来,当前在非发布线程中处理的事件将会由于新事件的发布,而暂停,等到新发布的事件结束后,才会接着执行.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值