源码阅读系列:EventBus

1,010 阅读1小时+

EventBus 是人们在日常开发中经常会用到的开源库,即使是不直接用的人,也多少借鉴过事件总线的用法。而且EventBus的代码其实是非常简单的,可以试着阅读一下。

源码阅读系列不采用对功能进行归类的方法进行阅读,而是采用一个刚开始阅读源码的视角,从我们平时的API调用,一步步的去理解设计意图和实现原理。

从这里开始

从这里开始吧,我们最常用的地方就是给一个函数添加上注解,我们先抛开apt生成的table,只看这个运行时版本的订阅设定。

// eventbus/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 (...)
        public void getMessage(Event event) { ... }
        

下面的问题是我们改怎么让EventBus找到这些方法呢?通过apt的版本我们知道这里面肯定有一个map或者是table的东西记录了Object和Method之间的订阅关系,而且还是一对多的。这个地方就是从每个我们进行register的地方进行的。

register & unregister

// eventbus/EventBus 
              /**
                 * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
                 * are no longer interested in receiving events.
                 * <p/>
                 * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
                 * The {@link Subscribe} annotation also allows configuration like {@link
                 * ThreadMode} and priority.
                 */
                public void register(Object subscriber) {
                    Class<?> subscriberClass = subscriber.getClass();
                    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
                    synchronized (this) {
                        for (SubscriberMethod subscriberMethod : subscriberMethods) {
                            subscribe(subscriber, subscriberMethod);
                        }
                    }
                }
                

我们在Activity/Fragment中都有可能会调用这个方法,如果是Fragment里面我们还会在onDestoryView()中进行unregister(...)。在这段函数里我们发现使用反射从这个Class中找到了所有的订阅者函数了,然后对每个订阅者函数进行注册。

这里我们看看我们的SubribeMethod被包装成了什么样子:

/** Used internally by EventBus and generated subscriber indexes. */
        public class SubscriberMethod {
            final Method method;
            final ThreadMode threadMode;
            final Class<?> eventType;
            final int priority;
            final boolean sticky;
            /** Used for efficient comparison */
            String methodString;
            public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
                this.method = method;
                this.threadMode = threadMode;
                this.eventType = eventType;
                this.priority = priority;
                this.sticky = sticky;
            }
            @Override
            public boolean equals(Object other) {
                if (other == this) {
                    return true;
                } else if (other instanceof SubscriberMethod) {
                    checkMethodString();
                    SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
                    otherSubscriberMethod.checkMethodString();
                    // Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
                    return methodString.equals(otherSubscriberMethod.methodString);
                } else {
                    return false;
                }
            }
            private synchronized void checkMethodString() {
                if (methodString == null) {
                    // Method.toString has more overhead, just take relevant parts of the method
                    StringBuilder builder = new StringBuilder(64);
                    builder.append(method.getDeclaringClass().getName());
                    builder.append('#').append(method.getName());
                    builder.append('(').append(eventType.getName());
                    methodString = builder.toString();
                }
            }
            @Override
            public int hashCode() {
                return method.hashCode();
            }
            }
            

SubscribeMethod 携带了Method函数原型,还有就是我们在注解类里面提供的所有信息。还有一个Class<?>类型的EventType是指我们的事件类所对应的Class,其余的方法都是为了比较和判断是否相等来做的,equal/checkMethodString都是各种的拼字串来进行存储和判断。

下面我们来看register里面调用的这段subscribe,这段非常的重要涉及了EventBus运行时处理的绝大多数部分,还有就是粘性事件的分发。这段使用了大量的JDK的反射包的API,本身注释也提醒我们了这段代码需要加锁,毕竟里面这一堆并发容器。所以我们最好先明确这段里面用的并发容器到底都是什么,这段代码才好继续看的下去。

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
        private final Map<Object, List<Class<?>>> typesBySubscriber;
        private final Map<Class<?>, Object> stickyEvents;
        

主要的有这几个:

  1. 第一个Map存储的Key是Class类型,Value是一个并发的ArrayList里面存的是对订阅者和订阅函数的一种绑定类Subscription从名字上也能看出Key是Event的Class对象。
  2. 第二个存储的是订阅者(Activity什么的啊)和Event类型的List。
  3. 第三个Map存储的是粘性事件,Key是Event类型,Value是真实存在的StickyEvent对象。

知道这三个都是什么之后,这段代码就好看了。我们来看前一部分。

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

这段写的虽然有点乱套,但实际上写的挺简单的,而且一堆堆的O(n)遍历,性能也就那样(?)。

首先这里面出现了Subscription:

final class Subscription {
            final Object subscriber;
            final SubscriberMethod subscriberMethod;
            /**
             * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
             * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
             */
            volatile boolean active;
            Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
                this.subscriber = subscriber;
                this.subscriberMethod = subscriberMethod;
                active = true;
            }
            @Override
            public boolean equals(Object other) {
                if (other instanceof Subscription) {
                    Subscription otherSubscription = (Subscription) other;
                    return subscriber == otherSubscription.subscriber
                            && subscriberMethod.equals(otherSubscription.subscriberMethod);
                } else {
                    return false;
                }
            }
            @Override
            public int hashCode() {
                return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
            }
            }
            

我们发现了这是订阅者和订阅方法类的一个契约关系类。

所以说上面subscribe函数主要做了,

  • 创建了订阅者和方法类的绑定,然后存进了subscriptionsByEventType
  • 对每个类型重新排列了一次优先级
  • typesBySubscriber添加了对应的类型

然后我们可以看一下这个函数的下一半,我们会惊奇地发现,StickyEvent的发送时机居然是在register的时候:

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

这时候轮了一遍所有的粘性事件。isAssignableFrom类似于使用在Class之间的instance of 就是判断两个类是否有相同的接口关系,也就是说有继承和实现关系的事件类,都会被判断处理。

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, Looper.getMainLooper() == Looper.myLooper());
              }
          }
          
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 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进行了处理,同一线程的直接依赖Java的反射invoke执行了,各种不可以的情况,比如说发到主线程但还没在主线程的时候,都是用队列进行发送到对应线程。

接下来我们看看这里面在各线程之间的发送是怎么实现的。

消息转换线程

我们发现在Subscription和event入队的时候我们把他们封装成了一个PendingPost类:

// HandlePoster    
        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");
                        }
                    }
                }
            }
            

然后才进行的入队和发送,这个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);
                    }
                }
            }
            }
            

这里的设计其实挺不错的,一个静态的回收池,初始化靠一个静态方法,优先使用被回收的对象,实现和Message其实很像。另一个release方法就是把用完的对象回收起来。

PendingPostQueue 就是一个PendingPost的队列,里面的操作基本上就是入队出队之类的,有点特殊的是入队和出队都有一把锁。

接着这个队列被用在了好几个Poster类中,实现了向各个线程的消息转换,首先我们来看向主线程发送数据的:

HandlePoster

final class HandlerPoster extends Handler {
                private final PendingPostQueue queue;
                private final int maxMillisInsideHandleMessage;
                private final EventBus eventBus;
                private boolean handlerActive;
                HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
                    super(looper);
                    this.eventBus = eventBus;
                    this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
                    queue = new PendingPostQueue();
                }
                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) {
                                if (!sendMessage(obtainMessage())) {
                                    throw new EventBusException("Could not send handler message");
                                }
                                rescheduled = true;
                                return;
                            }
                        }
                    } finally {
                        handlerActive = rescheduled;
                    }
                }
                }
                

HandlePoster 继承自 Handler 再加上初始化的时候传进去的是Looper.getMainThread();所以能向主线程发送消息。每次入队之后都会发送一条空消息去通知handleMessage函数处理队列数据,使用handlerActive作为控制标记位。handleMessage是个死循环两段的if判断用来处理多线程的情况,invokeSubscriber的方式和之前类似。之后就是有一个阀值,当时间超过10ms的时候就会发一个消息重入,并且退出这次循环,这是防止时间太长阻塞主线程。

BackgroundPoster

final class BackgroundPoster implements Runnable {
                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) {
                            Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
                        }
                    } finally {
                        executorRunning = false;
                    }
                }
                }
                

BackgroundPoster 自身是一个Runnable ,入队之后就调用EventBus携带的一个线程池进行运行,同样也是一个死循环,用了一个生产者 vs 消费者模式 进行了有限等待,这1000ms内入队的消息都会被弹出处理。

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

PendingPostQueue的poll(int)方法对队列为空的情况进行了等待,唤醒则出现在enqueue:

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(); // 在这进行了唤醒
            }
            

AsyncPoster

如果说Background尚且能保证在同一个线程内完成,AsyncPoster就完全进行了异步操作。

class AsyncPoster implements Runnable {
            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);
            }
            }
            

这里面基本上什么都不控制,直接就来一个运行一次,也不会有什么问题。。。

到这为止我们不但知道了方法是怎么注册和绑定的,我们甚至还知道了粘性事件是怎么发送的了,接着我们来看方法查找和普通事件的发送是怎么进行的。

方法查找

// package org.greenrobot.eventbus.meta;
            /** Base class for generated index classes created by annotation processing. */
            public interface SubscriberInfo {
                // 获取订阅的类
                Class<?> getSubscriberClass();
               // 所有的method
                SubscriberMethod[] getSubscriberMethods();
              // 获取父类的info
                SubscriberInfo getSuperSubscriberInfo();
                // 是否检查父类
                boolean shouldCheckSuperclass();
                }
                

SubscriberInfo 描述了能通过注解类生成的Index的方法(具体功能我加了主食)。

/**
         * Interface for generated indexes.
         */
         public interface SubscriberInfoIndex {
            SubscriberInfo getSubscriberInfo(Class<?> subscriberClass);
            }
            

这个接口是查找info的。

另外可以说这其中的SubscriberMethodInfo存储着SubscriberMethod所需的元信息:

public class SubscriberMethodInfo {
            final String methodName;
            final ThreadMode threadMode;
            final Class<?> eventType;
            final int priority;
            final boolean sticky;
          ...
          

AbstractSubscriberInfo是一个抽象类,主要负责从Info创建出Method,又是一个反射:

protected SubscriberMethod createSubscriberMethod(String methodName, Class<?> eventType, ThreadMode threadMode,
                                                          int priority, boolean sticky) {
            try {
                Method method = subscriberClass.getDeclaredMethod(methodName, eventType);
                return new SubscriberMethod(method, eventType, threadMode, priority, sticky);
            } catch (NoSuchMethodException e) {
                throw new EventBusException("Could not find subscriber method in " + subscriberClass +
                        ". Maybe a missing ProGuard rule?", e);
            }
            }
            

另外还有一个SimpleSubscriberInfo作为他的子类。

接下来的SubscriberMethodFinder也非常重要运行时的方法查找都来自这里:

刚才我们在EventBus.register(...)中调用了这个函数:

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

其中的METHOD_CACHE是对每个类方法进行缓存,防止多次查找,毕竟运行时查找还是个复杂的操作,根据是否忽略生成Index。

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

findUsingReflectionInSingleClass对反射类进行了处理,这里面通过掩模运算检查了访问权限, 检查了参数个数。

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)) {
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    // Put any non-Method object to "consume" the existing Method
                    anyMethodByEventType.put(eventType, this);
                }
                return checkAddWithMethodSignature(method, eventType);
            }
            }
            

其中的checkAdd检查了类型和方法签名,每次轮转完成之后都会进行一次findState.moveToSuperclass();对父类进行处理。

使用索引

因为反射所使用的运行时查找速度缓慢,所以我们也经常会通过apt使用已经创建好的Index。

刚才另一个分支的findUsingInfo就是使用已有的Index:

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

这段非常简单,几乎就是刚才的验证而已,如果没拿到数据的话,还会进行正常的反射查找。

// EventBusAnnotationProcessor 负责生成注解路由表
           private void createInfoIndexFile(String index) {
               BufferedWriter writer = null;
               try {
                   JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index);
                   int period = index.lastIndexOf('.');
                   String myPackage = period > 0 ? index.substring(0, period) : null;
                   String clazz = index.substring(period + 1);
                   writer = new BufferedWriter(sourceFile.openWriter());
                   if (myPackage != null) {
                       writer.write("package " + myPackage + ";\n\n");
                   }
                   writer.write("import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;\n");
                   writer.write("import org.greenrobot.eventbus.meta.SubscriberMethodInfo;\n");
                   writer.write("import org.greenrobot.eventbus.meta.SubscriberInfo;\n");
                   writer.write("import org.greenrobot.eventbus.meta.SubscriberInfoIndex;\n\n");
                   writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n");
                   writer.write("import java.util.HashMap;\n");
                   writer.write("import java.util.Map;\n\n");
                   writer.write("/** This class is generated by EventBus, do not edit. */\n");
                   writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n");
                   writer.write("    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;\n\n");
                   writer.write("    static {\n");
                   writer.write("        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();\n\n");
                   writeIndexLines(writer, myPackage);
                   writer.write("    }\n\n");
                   writer.write("    private static void putIndex(SubscriberInfo info) {\n");
                   writer.write("        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);\n");
                   writer.write("    }\n\n");
                   writer.write("    @Override\n");
                   writer.write("    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {\n");
                   writer.write("        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);\n");
                   writer.write("        if (info != null) {\n");
                   writer.write("            return info;\n");
                   writer.write("        } else {\n");
                   writer.write("            return null;\n");
                   writer.write("        }\n");
                   writer.write("    }\n");
                   writer.write("}\n");
               } catch (IOException e) {
                   throw new RuntimeException("Could not write source for " + index, e);
               } finally {
                   if (writer != null) {
                       try {
                           writer.close();
                       } catch (IOException e) {
                           //Silent
                       }
                   }
               }
           }
           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");
                   }
               }
           }
           

有了这两个方法之后我们就知道,平常的index就是通过这种方式拼接出来的。

Post消息

/** Posts the given event to the event bus. */
            public void post(Object event) {
                PostingThreadState postingState = currentPostingThreadState.get();
                List<Object> eventQueue = postingState.eventQueue;
                eventQueue.add(event);
                if (!postingState.isPosting) {
                    postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
                    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;
                    }
                }
                }
                

PostingThreadState是一个存储在ThreadLocal中的对象,包含有以下各种内容,线程信息,是否是主线程,是否取消,还有一个相应的事件队列。

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
              Class<?> eventClass = event.getClass();
              boolean subscriptionFound = false;
              if (eventInheritance) {
                    /** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */
                  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) {
                      Log.d(TAG, "No subscribers registered for event " + eventClass);
                  }
                  if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                          eventClass != SubscriberExceptionEvent.class) {
                      // 无订阅者的处理
                      post(new NoSubscriberEvent(this, event));
                  }
              }
          }
          

之后:

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

之后对所有的订阅类的所有订阅者都发送一次数据,发送数据方法和上文相同。

发送粘性数据就是拿锁然后保存到队列中去,这样就可以在重新发送:

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

因为我们无法确定什么时候粘性事件应该停止继续传播,这取决于我们应用的需要,所以我们应当手动remove掉Sticky Event :

// 系统提供了如下方法
         public <T> T removeStickyEvent(Class<T> eventType) {
                synchronized (stickyEvents) {
                    return eventType.cast(stickyEvents.remove(eventType));
                }
            }
            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;
                    }
                }
            }
            public void removeAllStickyEvents() {
                synchronized (stickyEvents) {
                    stickyEvents.clear();
                }
            }
            

至此我们就分析完了EventBus的基本上所有的代码(处理util包下的错误日志),EventBus本身的实现并不复杂,使用运行时的反射技巧也很简单,单纯的使用注解类可能会拖慢速度,但是通过apt生成的静态表把速降提升到了一个新的高度,apt的生成大家也看到了并不是很复杂,几乎就是类型检查和拼接字串,不过想法决定了EventBus仍然是一个优秀的开源库,希望我们在使用的同时,仍能对实现原理有所了解。

EventBus 是人们在日常开发中经常会用到的开源库,即使是不直接用的人,也多少借鉴过事件总线的用法。而且EventBus的代码其实是非常简单的,可以试着阅读一下。

源码阅读系列不采用对功能进行归类的方法进行阅读,而是采用一个刚开始阅读源码的视角,从我们平时的API调用,一步步的去理解设计意图和实现原理。

从这里开始

从这里开始吧,我们最常用的地方就是给一个函数添加上注解,我们先抛开apt生成的table,只看这个运行时版本的订阅设定。

// eventbus/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 (...)
        public void getMessage(Event event) { ... }
        

下面的问题是我们改怎么让EventBus找到这些方法呢?通过apt的版本我们知道这里面肯定有一个map或者是table的东西记录了Object和Method之间的订阅关系,而且还是一对多的。这个地方就是从每个我们进行register的地方进行的。

register & unregister

// eventbus/EventBus 
              /**
                 * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
                 * are no longer interested in receiving events.
                 * <p/>
                 * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
                 * The {@link Subscribe} annotation also allows configuration like {@link
                 * ThreadMode} and priority.
                 */
                public void register(Object subscriber) {
                    Class<?> subscriberClass = subscriber.getClass();
                    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
                    synchronized (this) {
                        for (SubscriberMethod subscriberMethod : subscriberMethods) {
                            subscribe(subscriber, subscriberMethod);
                        }
                    }
                }
                

我们在Activity/Fragment中都有可能会调用这个方法,如果是Fragment里面我们还会在onDestoryView()中进行unregister(...)。在这段函数里我们发现使用反射从这个Class中找到了所有的订阅者函数了,然后对每个订阅者函数进行注册。

这里我们看看我们的SubribeMethod被包装成了什么样子:

/** Used internally by EventBus and generated subscriber indexes. */
        public class SubscriberMethod {
            final Method method;
            final ThreadMode threadMode;
            final Class<?> eventType;
            final int priority;
            final boolean sticky;
            /** Used for efficient comparison */
            String methodString;
            public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
                this.method = method;
                this.threadMode = threadMode;
                this.eventType = eventType;
                this.priority = priority;
                this.sticky = sticky;
            }
            @Override
            public boolean equals(Object other) {
                if (other == this) {
                    return true;
                } else if (other instanceof SubscriberMethod) {
                    checkMethodString();
                    SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
                    otherSubscriberMethod.checkMethodString();
                    // Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
                    return methodString.equals(otherSubscriberMethod.methodString);
                } else {
                    return false;
                }
            }
            private synchronized void checkMethodString() {
                if (methodString == null) {
                    // Method.toString has more overhead, just take relevant parts of the method
                    StringBuilder builder = new StringBuilder(64);
                    builder.append(method.getDeclaringClass().getName());
                    builder.append('#').append(method.getName());
                    builder.append('(').append(eventType.getName());
                    methodString = builder.toString();
                }
            }
            @Override
            public int hashCode() {
                return method.hashCode();
            }
            }
            

SubscribeMethod 携带了Method函数原型,还有就是我们在注解类里面提供的所有信息。还有一个Class<?>类型的EventType是指我们的事件类所对应的Class,其余的方法都是为了比较和判断是否相等来做的,equal/checkMethodString都是各种的拼字串来进行存储和判断。

下面我们来看register里面调用的这段subscribe,这段非常的重要涉及了EventBus运行时处理的绝大多数部分,还有就是粘性事件的分发。这段使用了大量的JDK的反射包的API,本身注释也提醒我们了这段代码需要加锁,毕竟里面这一堆并发容器。所以我们最好先明确这段里面用的并发容器到底都是什么,这段代码才好继续看的下去。

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
        private final Map<Object, List<Class<?>>> typesBySubscriber;
        private final Map<Class<?>, Object> stickyEvents;
        

主要的有这几个:

  1. 第一个Map存储的Key是Class类型,Value是一个并发的ArrayList里面存的是对订阅者和订阅函数的一种绑定类Subscription从名字上也能看出Key是Event的Class对象。
  2. 第二个存储的是订阅者(Activity什么的啊)和Event类型的List。
  3. 第三个Map存储的是粘性事件,Key是Event类型,Value是真实存在的StickyEvent对象。

知道这三个都是什么之后,这段代码就好看了。我们来看前一部分。

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

这段写的虽然有点乱套,但实际上写的挺简单的,而且一堆堆的O(n)遍历,性能也就那样(?)。

首先这里面出现了Subscription:

final class Subscription {
            final Object subscriber;
            final SubscriberMethod subscriberMethod;
            /**
             * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
             * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
             */
            volatile boolean active;
            Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
                this.subscriber = subscriber;
                this.subscriberMethod = subscriberMethod;
                active = true;
            }
            @Override
            public boolean equals(Object other) {
                if (other instanceof Subscription) {
                    Subscription otherSubscription = (Subscription) other;
                    return subscriber == otherSubscription.subscriber
                            && subscriberMethod.equals(otherSubscription.subscriberMethod);
                } else {
                    return false;
                }
            }
            @Override
            public int hashCode() {
                return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
            }
            }
            

我们发现了这是订阅者和订阅方法类的一个契约关系类。

所以说上面subscribe函数主要做了,

  • 创建了订阅者和方法类的绑定,然后存进了subscriptionsByEventType
  • 对每个类型重新排列了一次优先级
  • typesBySubscriber添加了对应的类型

然后我们可以看一下这个函数的下一半,我们会惊奇地发现,StickyEvent的发送时机居然是在register的时候:

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

这时候轮了一遍所有的粘性事件。isAssignableFrom类似于使用在Class之间的instance of 就是判断两个类是否有相同的接口关系,也就是说有继承和实现关系的事件类,都会被判断处理。

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, Looper.getMainLooper() == Looper.myLooper());
              }
          }
          
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 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进行了处理,同一线程的直接依赖Java的反射invoke执行了,各种不可以的情况,比如说发到主线程但还没在主线程的时候,都是用队列进行发送到对应线程。

接下来我们看看这里面在各线程之间的发送是怎么实现的。

消息转换线程

我们发现在Subscription和event入队的时候我们把他们封装成了一个PendingPost类:

// HandlePoster    
        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");
                        }
                    }
                }
            }
            

然后才进行的入队和发送,这个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);
                    }
                }
            }
            }
            

这里的设计其实挺不错的,一个静态的回收池,初始化靠一个静态方法,优先使用被回收的对象,实现和Message其实很像。另一个release方法就是把用完的对象回收起来。

PendingPostQueue 就是一个PendingPost的队列,里面的操作基本上就是入队出队之类的,有点特殊的是入队和出队都有一把锁。

接着这个队列被用在了好几个Poster类中,实现了向各个线程的消息转换,首先我们来看向主线程发送数据的:

HandlePoster

final class HandlerPoster extends Handler {
                private final PendingPostQueue queue;
                private final int maxMillisInsideHandleMessage;
                private final EventBus eventBus;
                private boolean handlerActive;
                HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
                    super(looper);
                    this.eventBus = eventBus;
                    this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
                    queue = new PendingPostQueue();
                }
                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) {
                                if (!sendMessage(obtainMessage())) {
                                    throw new EventBusException("Could not send handler message");
                                }
                                rescheduled = true;
                                return;
                            }
                        }
                    } finally {
                        handlerActive = rescheduled;
                    }
                }
                }
                

HandlePoster 继承自 Handler 再加上初始化的时候传进去的是Looper.getMainThread();所以能向主线程发送消息。每次入队之后都会发送一条空消息去通知handleMessage函数处理队列数据,使用handlerActive作为控制标记位。handleMessage是个死循环两段的if判断用来处理多线程的情况,invokeSubscriber的方式和之前类似。之后就是有一个阀值,当时间超过10ms的时候就会发一个消息重入,并且退出这次循环,这是防止时间太长阻塞主线程。

BackgroundPoster

final class BackgroundPoster implements Runnable {
                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) {
                            Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
                        }
                    } finally {
                        executorRunning = false;
                    }
                }
                }
                

BackgroundPoster 自身是一个Runnable ,入队之后就调用EventBus携带的一个线程池进行运行,同样也是一个死循环,用了一个生产者 vs 消费者模式 进行了有限等待,这1000ms内入队的消息都会被弹出处理。

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

PendingPostQueue的poll(int)方法对队列为空的情况进行了等待,唤醒则出现在enqueue:

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(); // 在这进行了唤醒
            }
            

AsyncPoster

如果说Background尚且能保证在同一个线程内完成,AsyncPoster就完全进行了异步操作。

class AsyncPoster implements Runnable {
            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);
            }
            }
            

这里面基本上什么都不控制,直接就来一个运行一次,也不会有什么问题。。。

到这为止我们不但知道了方法是怎么注册和绑定的,我们甚至还知道了粘性事件是怎么发送的了,接着我们来看方法查找和普通事件的发送是怎么进行的。

方法查找

// package org.greenrobot.eventbus.meta;
            /** Base class for generated index classes created by annotation processing. */
            public interface SubscriberInfo {
                // 获取订阅的类
                Class<?> getSubscriberClass();
               // 所有的method
                SubscriberMethod[] getSubscriberMethods();
              // 获取父类的info
                SubscriberInfo getSuperSubscriberInfo();
                // 是否检查父类
                boolean shouldCheckSuperclass();
                }
                

SubscriberInfo 描述了能通过注解类生成的Index的方法(具体功能我加了主食)。

/**
         * Interface for generated indexes.
         */
         public interface SubscriberInfoIndex {
            SubscriberInfo getSubscriberInfo(Class<?> subscriberClass);
            }
            

这个接口是查找info的。

另外可以说这其中的SubscriberMethodInfo存储着SubscriberMethod所需的元信息:

public class SubscriberMethodInfo {
            final String methodName;
            final ThreadMode threadMode;
            final Class<?> eventType;
            final int priority;
            final boolean sticky;
          ...
          

AbstractSubscriberInfo是一个抽象类,主要负责从Info创建出Method,又是一个反射:

protected SubscriberMethod createSubscriberMethod(String methodName, Class<?> eventType, ThreadMode threadMode,
                                                          int priority, boolean sticky) {
            try {
                Method method = subscriberClass.getDeclaredMethod(methodName, eventType);
                return new SubscriberMethod(method, eventType, threadMode, priority, sticky);
            } catch (NoSuchMethodException e) {
                throw new EventBusException("Could not find subscriber method in " + subscriberClass +
                        ". Maybe a missing ProGuard rule?", e);
            }
            }
            

另外还有一个SimpleSubscriberInfo作为他的子类。

接下来的SubscriberMethodFinder也非常重要运行时的方法查找都来自这里:

刚才我们在EventBus.register(...)中调用了这个函数:

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

其中的METHOD_CACHE是对每个类方法进行缓存,防止多次查找,毕竟运行时查找还是个复杂的操作,根据是否忽略生成Index。

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

findUsingReflectionInSingleClass对反射类进行了处理,这里面通过掩模运算检查了访问权限, 检查了参数个数。

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)) {
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    // Put any non-Method object to "consume" the existing Method
                    anyMethodByEventType.put(eventType, this);
                }
                return checkAddWithMethodSignature(method, eventType);
            }
            }
            

其中的checkAdd检查了类型和方法签名,每次轮转完成之后都会进行一次findState.moveToSuperclass();对父类进行处理。

使用索引

因为反射所使用的运行时查找速度缓慢,所以我们也经常会通过apt使用已经创建好的Index。

刚才另一个分支的findUsingInfo就是使用已有的Index:

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

这段非常简单,几乎就是刚才的验证而已,如果没拿到数据的话,还会进行正常的反射查找。

// EventBusAnnotationProcessor 负责生成注解路由表
           private void createInfoIndexFile(String index) {
               BufferedWriter writer = null;
               try {
                   JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index);
                   int period = index.lastIndexOf('.');
                   String myPackage = period > 0 ? index.substring(0, period) : null;
                   String clazz = index.substring(period + 1);
                   writer = new BufferedWriter(sourceFile.openWriter());
                   if (myPackage != null) {
                       writer.write("package " + myPackage + ";\n\n");
                   }
                   writer.write("import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;\n");
                   writer.write("import org.greenrobot.eventbus.meta.SubscriberMethodInfo;\n");
                   writer.write("import org.greenrobot.eventbus.meta.SubscriberInfo;\n");
                   writer.write("import org.greenrobot.eventbus.meta.SubscriberInfoIndex;\n\n");
                   writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n");
                   writer.write("import java.util.HashMap;\n");
                   writer.write("import java.util.Map;\n\n");
                   writer.write("/** This class is generated by EventBus, do not edit. */\n");
                   writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n");
                   writer.write("    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;\n\n");
                   writer.write("    static {\n");
                   writer.write("        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();\n\n");
                   writeIndexLines(writer, myPackage);
                   writer.write("    }\n\n");
                   writer.write("    private static void putIndex(SubscriberInfo info) {\n");
                   writer.write("        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);\n");
                   writer.write("    }\n\n");
                   writer.write("    @Override\n");
                   writer.write("    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {\n");
                   writer.write("        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);\n");
                   writer.write("        if (info != null) {\n");
                   writer.write("            return info;\n");
                   writer.write("        } else {\n");
                   writer.write("            return null;\n");
                   writer.write("        }\n");
                   writer.write("    }\n");
                   writer.write("}\n");
               } catch (IOException e) {
                   throw new RuntimeException("Could not write source for " + index, e);
               } finally {
                   if (writer != null) {
                       try {
                           writer.close();
                       } catch (IOException e) {
                           //Silent
                       }
                   }
               }
           }
           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");
                   }
               }
           }
           

有了这两个方法之后我们就知道,平常的index就是通过这种方式拼接出来的。

Post消息

/** Posts the given event to the event bus. */
            public void post(Object event) {
                PostingThreadState postingState = currentPostingThreadState.get();
                List<Object> eventQueue = postingState.eventQueue;
                eventQueue.add(event);
                if (!postingState.isPosting) {
                    postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
                    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;
                    }
                }
                }
                

PostingThreadState是一个存储在ThreadLocal中的对象,包含有以下各种内容,线程信息,是否是主线程,是否取消,还有一个相应的事件队列。

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
              Class<?> eventClass = event.getClass();
              boolean subscriptionFound = false;
              if (eventInheritance) {
                    /** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */
                  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) {
                      Log.d(TAG, "No subscribers registered for event " + eventClass);
                  }
                  if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                          eventClass != SubscriberExceptionEvent.class) {
                      // 无订阅者的处理
                      post(new NoSubscriberEvent(this, event));
                  }
              }
          }
          

之后:

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

之后对所有的订阅类的所有订阅者都发送一次数据,发送数据方法和上文相同。

发送粘性数据就是拿锁然后保存到队列中去,这样就可以在重新发送:

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

因为我们无法确定什么时候粘性事件应该停止继续传播,这取决于我们应用的需要,所以我们应当手动remove掉Sticky Event :

// 系统提供了如下方法
         public <T> T removeStickyEvent(Class<T> eventType) {
                synchronized (stickyEvents) {
                    return eventType.cast(stickyEvents.remove(eventType));
                }
            }
            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;
                    }
                }
            }
            public void removeAllStickyEvents() {
                synchronized (stickyEvents) {
                    stickyEvents.clear();
                }
            }
            

至此我们就分析完了EventBus的基本上所有的代码(处理util包下的错误日志),EventBus本身的实现并不复杂,使用运行时的反射技巧也很简单,单纯的使用注解类可能会拖慢速度,但是通过apt生成的静态表把速降提升到了一个新的高度,apt的生成大家也看到了并不是很复杂,几乎就是类型检查和拼接字串,不过想法决定了EventBus仍然是一个优秀的开源库,希望我们在使用的同时,仍能对实现原理有所了解。

EventBus 是人们在日常开发中经常会用到的开源库,即使是不直接用的人,也多少借鉴过事件总线的用法。而且EventBus的代码其实是非常简单的,可以试着阅读一下。

源码阅读系列不采用对功能进行归类的方法进行阅读,而是采用一个刚开始阅读源码的视角,从我们平时的API调用,一步步的去理解设计意图和实现原理。

从这里开始

从这里开始吧,我们最常用的地方就是给一个函数添加上注解,我们先抛开apt生成的table,只看这个运行时版本的订阅设定。

// eventbus/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 (...)
        public void getMessage(Event event) { ... }
        

下面的问题是我们改怎么让EventBus找到这些方法呢?通过apt的版本我们知道这里面肯定有一个map或者是table的东西记录了Object和Method之间的订阅关系,而且还是一对多的。这个地方就是从每个我们进行register的地方进行的。

register & unregister

// eventbus/EventBus 
              /**
                 * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
                 * are no longer interested in receiving events.
                 * <p/>
                 * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
                 * The {@link Subscribe} annotation also allows configuration like {@link
                 * ThreadMode} and priority.
                 */
                public void register(Object subscriber) {
                    Class<?> subscriberClass = subscriber.getClass();
                    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
                    synchronized (this) {
                        for (SubscriberMethod subscriberMethod : subscriberMethods) {
                            subscribe(subscriber, subscriberMethod);
                        }
                    }
                }
                

我们在Activity/Fragment中都有可能会调用这个方法,如果是Fragment里面我们还会在onDestoryView()中进行unregister(...)。在这段函数里我们发现使用反射从这个Class中找到了所有的订阅者函数了,然后对每个订阅者函数进行注册。

这里我们看看我们的SubribeMethod被包装成了什么样子:

/** Used internally by EventBus and generated subscriber indexes. */
        public class SubscriberMethod {
            final Method method;
            final ThreadMode threadMode;
            final Class<?> eventType;
            final int priority;
            final boolean sticky;
            /** Used for efficient comparison */
            String methodString;
            public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
                this.method = method;
                this.threadMode = threadMode;
                this.eventType = eventType;
                this.priority = priority;
                this.sticky = sticky;
            }
            @Override
            public boolean equals(Object other) {
                if (other == this) {
                    return true;
                } else if (other instanceof SubscriberMethod) {
                    checkMethodString();
                    SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
                    otherSubscriberMethod.checkMethodString();
                    // Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
                    return methodString.equals(otherSubscriberMethod.methodString);
                } else {
                    return false;
                }
            }
            private synchronized void checkMethodString() {
                if (methodString == null) {
                    // Method.toString has more overhead, just take relevant parts of the method
                    StringBuilder builder = new StringBuilder(64);
                    builder.append(method.getDeclaringClass().getName());
                    builder.append('#').append(method.getName());
                    builder.append('(').append(eventType.getName());
                    methodString = builder.toString();
                }
            }
            @Override
            public int hashCode() {
                return method.hashCode();
            }
            }
            

SubscribeMethod 携带了Method函数原型,还有就是我们在注解类里面提供的所有信息。还有一个Class<?>类型的EventType是指我们的事件类所对应的Class,其余的方法都是为了比较和判断是否相等来做的,equal/checkMethodString都是各种的拼字串来进行存储和判断。

下面我们来看register里面调用的这段subscribe,这段非常的重要涉及了EventBus运行时处理的绝大多数部分,还有就是粘性事件的分发。这段使用了大量的JDK的反射包的API,本身注释也提醒我们了这段代码需要加锁,毕竟里面这一堆并发容器。所以我们最好先明确这段里面用的并发容器到底都是什么,这段代码才好继续看的下去。

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
        private final Map<Object, List<Class<?>>> typesBySubscriber;
        private final Map<Class<?>, Object> stickyEvents;
        

主要的有这几个:

  1. 第一个Map存储的Key是Class类型,Value是一个并发的ArrayList里面存的是对订阅者和订阅函数的一种绑定类Subscription从名字上也能看出Key是Event的Class对象。
  2. 第二个存储的是订阅者(Activity什么的啊)和Event类型的List。
  3. 第三个Map存储的是粘性事件,Key是Event类型,Value是真实存在的StickyEvent对象。

知道这三个都是什么之后,这段代码就好看了。我们来看前一部分。

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

这段写的虽然有点乱套,但实际上写的挺简单的,而且一堆堆的O(n)遍历,性能也就那样(?)。

首先这里面出现了Subscription:

final class Subscription {
            final Object subscriber;
            final SubscriberMethod subscriberMethod;
            /**
             * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
             * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
             */
            volatile boolean active;
            Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
                this.subscriber = subscriber;
                this.subscriberMethod = subscriberMethod;
                active = true;
            }
            @Override
            public boolean equals(Object other) {
                if (other instanceof Subscription) {
                    Subscription otherSubscription = (Subscription) other;
                    return subscriber == otherSubscription.subscriber
                            && subscriberMethod.equals(otherSubscription.subscriberMethod);
                } else {
                    return false;
                }
            }
            @Override
            public int hashCode() {
                return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
            }
            }
            

我们发现了这是订阅者和订阅方法类的一个契约关系类。

所以说上面subscribe函数主要做了,

  • 创建了订阅者和方法类的绑定,然后存进了subscriptionsByEventType
  • 对每个类型重新排列了一次优先级
  • typesBySubscriber添加了对应的类型

然后我们可以看一下这个函数的下一半,我们会惊奇地发现,StickyEvent的发送时机居然是在register的时候:

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

这时候轮了一遍所有的粘性事件。isAssignableFrom类似于使用在Class之间的instance of 就是判断两个类是否有相同的接口关系,也就是说有继承和实现关系的事件类,都会被判断处理。

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, Looper.getMainLooper() == Looper.myLooper());
              }
          }
          
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 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进行了处理,同一线程的直接依赖Java的反射invoke执行了,各种不可以的情况,比如说发到主线程但还没在主线程的时候,都是用队列进行发送到对应线程。

接下来我们看看这里面在各线程之间的发送是怎么实现的。

消息转换线程

我们发现在Subscription和event入队的时候我们把他们封装成了一个PendingPost类:

// HandlePoster    
        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");
                        }
                    }
                }
            }
            

然后才进行的入队和发送,这个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);
                    }
                }
            }
            }
            

这里的设计其实挺不错的,一个静态的回收池,初始化靠一个静态方法,优先使用被回收的对象,实现和Message其实很像。另一个release方法就是把用完的对象回收起来。

PendingPostQueue 就是一个PendingPost的队列,里面的操作基本上就是入队出队之类的,有点特殊的是入队和出队都有一把锁。

接着这个队列被用在了好几个Poster类中,实现了向各个线程的消息转换,首先我们来看向主线程发送数据的:

HandlePoster

final class HandlerPoster extends Handler {
                private final PendingPostQueue queue;
                private final int maxMillisInsideHandleMessage;
                private final EventBus eventBus;
                private boolean handlerActive;
                HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
                    super(looper);
                    this.eventBus = eventBus;
                    this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
                    queue = new PendingPostQueue();
                }
                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) {
                                if (!sendMessage(obtainMessage())) {
                                    throw new EventBusException("Could not send handler message");
                                }
                                rescheduled = true;
                                return;
                            }
                        }
                    } finally {
                        handlerActive = rescheduled;
                    }
                }
                }
                

HandlePoster 继承自 Handler 再加上初始化的时候传进去的是Looper.getMainThread();所以能向主线程发送消息。每次入队之后都会发送一条空消息去通知handleMessage函数处理队列数据,使用handlerActive作为控制标记位。handleMessage是个死循环两段的if判断用来处理多线程的情况,invokeSubscriber的方式和之前类似。之后就是有一个阀值,当时间超过10ms的时候就会发一个消息重入,并且退出这次循环,这是防止时间太长阻塞主线程。

BackgroundPoster

final class BackgroundPoster implements Runnable {
                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) {
                            Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
                        }
                    } finally {
                        executorRunning = false;
                    }
                }
                }
                

BackgroundPoster 自身是一个Runnable ,入队之后就调用EventBus携带的一个线程池进行运行,同样也是一个死循环,用了一个生产者 vs 消费者模式 进行了有限等待,这1000ms内入队的消息都会被弹出处理。

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

PendingPostQueue的poll(int)方法对队列为空的情况进行了等待,唤醒则出现在enqueue:

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(); // 在这进行了唤醒
            }
            

AsyncPoster

如果说Background尚且能保证在同一个线程内完成,AsyncPoster就完全进行了异步操作。

class AsyncPoster implements Runnable {
            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);
            }
            }
            

这里面基本上什么都不控制,直接就来一个运行一次,也不会有什么问题。。。

到这为止我们不但知道了方法是怎么注册和绑定的,我们甚至还知道了粘性事件是怎么发送的了,接着我们来看方法查找和普通事件的发送是怎么进行的。

方法查找

// package org.greenrobot.eventbus.meta;
            /** Base class for generated index classes created by annotation processing. */
            public interface SubscriberInfo {
                // 获取订阅的类
                Class<?> getSubscriberClass();
               // 所有的method
                SubscriberMethod[] getSubscriberMethods();
              // 获取父类的info
                SubscriberInfo getSuperSubscriberInfo();
                // 是否检查父类
                boolean shouldCheckSuperclass();
                }
                

SubscriberInfo 描述了能通过注解类生成的Index的方法(具体功能我加了主食)。

/**
         * Interface for generated indexes.
         */
         public interface SubscriberInfoIndex {
            SubscriberInfo getSubscriberInfo(Class<?> subscriberClass);
            }
            

这个接口是查找info的。

另外可以说这其中的SubscriberMethodInfo存储着SubscriberMethod所需的元信息:

public class SubscriberMethodInfo {
            final String methodName;
            final ThreadMode threadMode;
            final Class<?> eventType;
            final int priority;
            final boolean sticky;
          ...
          

AbstractSubscriberInfo是一个抽象类,主要负责从Info创建出Method,又是一个反射:

protected SubscriberMethod createSubscriberMethod(String methodName, Class<?> eventType, ThreadMode threadMode,
                                                          int priority, boolean sticky) {
            try {
                Method method = subscriberClass.getDeclaredMethod(methodName, eventType);
                return new SubscriberMethod(method, eventType, threadMode, priority, sticky);
            } catch (NoSuchMethodException e) {
                throw new EventBusException("Could not find subscriber method in " + subscriberClass +
                        ". Maybe a missing ProGuard rule?", e);
            }
            }
            

另外还有一个SimpleSubscriberInfo作为他的子类。

接下来的SubscriberMethodFinder也非常重要运行时的方法查找都来自这里:

刚才我们在EventBus.register(...)中调用了这个函数:

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

其中的METHOD_CACHE是对每个类方法进行缓存,防止多次查找,毕竟运行时查找还是个复杂的操作,根据是否忽略生成Index。

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

findUsingReflectionInSingleClass对反射类进行了处理,这里面通过掩模运算检查了访问权限, 检查了参数个数。

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)) {
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    // Put any non-Method object to "consume" the existing Method
                    anyMethodByEventType.put(eventType, this);
                }
                return checkAddWithMethodSignature(method, eventType);
            }
            }
            

其中的checkAdd检查了类型和方法签名,每次轮转完成之后都会进行一次findState.moveToSuperclass();对父类进行处理。

使用索引

因为反射所使用的运行时查找速度缓慢,所以我们也经常会通过apt使用已经创建好的Index。

刚才另一个分支的findUsingInfo就是使用已有的Index:

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

这段非常简单,几乎就是刚才的验证而已,如果没拿到数据的话,还会进行正常的反射查找。

// EventBusAnnotationProcessor 负责生成注解路由表
           private void createInfoIndexFile(String index) {
               BufferedWriter writer = null;
               try {
                   JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index);
                   int period = index.lastIndexOf('.');
                   String myPackage = period > 0 ? index.substring(0, period) : null;
                   String clazz = index.substring(period + 1);
                   writer = new BufferedWriter(sourceFile.openWriter());
                   if (myPackage != null) {
                       writer.write("package " + myPackage + ";\n\n");
                   }
                   writer.write("import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;\n");
                   writer.write("import org.greenrobot.eventbus.meta.SubscriberMethodInfo;\n");
                   writer.write("import org.greenrobot.eventbus.meta.SubscriberInfo;\n");
                   writer.write("import org.greenrobot.eventbus.meta.SubscriberInfoIndex;\n\n");
                   writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n");
                   writer.write("import java.util.HashMap;\n");
                   writer.write("import java.util.Map;\n\n");
                   writer.write("/** This class is generated by EventBus, do not edit. */\n");
                   writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n");
                   writer.write("    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;\n\n");
                   writer.write("    static {\n");
                   writer.write("        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();\n\n");
                   writeIndexLines(writer, myPackage);
                   writer.write("    }\n\n");
                   writer.write("    private static void putIndex(SubscriberInfo info) {\n");
                   writer.write("        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);\n");
                   writer.write("    }\n\n");
                   writer.write("    @Override\n");
                   writer.write("    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {\n");
                   writer.write("        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);\n");
                   writer.write("        if (info != null) {\n");
                   writer.write("            return info;\n");
                   writer.write("        } else {\n");
                   writer.write("            return null;\n");
                   writer.write("        }\n");
                   writer.write("    }\n");
                   writer.write("}\n");
               } catch (IOException e) {
                   throw new RuntimeException("Could not write source for " + index, e);
               } finally {
                   if (writer != null) {
                       try {
                           writer.close();
                       } catch (IOException e) {
                           //Silent
                       }
                   }
               }
           }
           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");
                   }
               }
           }
           

有了这两个方法之后我们就知道,平常的index就是通过这种方式拼接出来的。

Post消息

/** Posts the given event to the event bus. */
            public void post(Object event) {
                PostingThreadState postingState = currentPostingThreadState.get();
                List<Object> eventQueue = postingState.eventQueue;
                eventQueue.add(event);
                if (!postingState.isPosting) {
                    postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
                    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;
                    }
                }
                }
                

PostingThreadState是一个存储在ThreadLocal中的对象,包含有以下各种内容,线程信息,是否是主线程,是否取消,还有一个相应的事件队列。

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
              Class<?> eventClass = event.getClass();
              boolean subscriptionFound = false;
              if (eventInheritance) {
                    /** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */
                  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) {
                      Log.d(TAG, "No subscribers registered for event " + eventClass);
                  }
                  if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                          eventClass != SubscriberExceptionEvent.class) {
                      // 无订阅者的处理
                      post(new NoSubscriberEvent(this, event));
                  }
              }
          }
          

之后:

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

之后对所有的订阅类的所有订阅者都发送一次数据,发送数据方法和上文相同。

发送粘性数据就是拿锁然后保存到队列中去,这样就可以在重新发送:

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

因为我们无法确定什么时候粘性事件应该停止继续传播,这取决于我们应用的需要,所以我们应当手动remove掉Sticky Event :

// 系统提供了如下方法
         public <T> T removeStickyEvent(Class<T> eventType) {
                synchronized (stickyEvents) {
                    return eventType.cast(stickyEvents.remove(eventType));
                }
            }
            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;
                    }
                }
            }
            public void removeAllStickyEvents() {
                synchronized (stickyEvents) {
                    stickyEvents.clear();
                }
            }
            

至此我们就分析完了EventBus的基本上所有的代码(处理util包下的错误日志),EventBus本身的实现并不复杂,使用运行时的反射技巧也很简单,单纯的使用注解类可能会拖慢速度,但是通过apt生成的静态表把速降提升到了一个新的高度,apt的生成大家也看到了并不是很复杂,几乎就是类型检查和拼接字串,不过想法决定了EventBus仍然是一个优秀的开源库,希望我们在使用的同时,仍能对实现原理有所了解。

EventBus 是人们在日常开发中经常会用到的开源库,即使是不直接用的人,也多少借鉴过事件总线的用法。而且EventBus的代码其实是非常简单的,可以试着阅读一下。

源码阅读系列不采用对功能进行归类的方法进行阅读,而是采用一个刚开始阅读源码的视角,从我们平时的API调用,一步步的去理解设计意图和实现原理。

从这里开始

从这里开始吧,我们最常用的地方就是给一个函数添加上注解,我们先抛开apt生成的table,只看这个运行时版本的订阅设定。

// eventbus/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 (...)
        public void getMessage(Event event) { ... }
        

下面的问题是我们改怎么让EventBus找到这些方法呢?通过apt的版本我们知道这里面肯定有一个map或者是table的东西记录了Object和Method之间的订阅关系,而且还是一对多的。这个地方就是从每个我们进行register的地方进行的。

register & unregister

// eventbus/EventBus 
              /**
                 * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
                 * are no longer interested in receiving events.
                 * <p/>
                 * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
                 * The {@link Subscribe} annotation also allows configuration like {@link
                 * ThreadMode} and priority.
                 */
                public void register(Object subscriber) {
                    Class<?> subscriberClass = subscriber.getClass();
                    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
                    synchronized (this) {
                        for (SubscriberMethod subscriberMethod : subscriberMethods) {
                            subscribe(subscriber, subscriberMethod);
                        }
                    }
                }
                

我们在Activity/Fragment中都有可能会调用这个方法,如果是Fragment里面我们还会在onDestoryView()中进行unregister(...)。在这段函数里我们发现使用反射从这个Class中找到了所有的订阅者函数了,然后对每个订阅者函数进行注册。

这里我们看看我们的SubribeMethod被包装成了什么样子:

/** Used internally by EventBus and generated subscriber indexes. */
        public class SubscriberMethod {
            final Method method;
            final ThreadMode threadMode;
            final Class<?> eventType;
            final int priority;
            final boolean sticky;
            /** Used for efficient comparison */
            String methodString;
            public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
                this.method = method;
                this.threadMode = threadMode;
                this.eventType = eventType;
                this.priority = priority;
                this.sticky = sticky;
            }
            @Override
            public boolean equals(Object other) {
                if (other == this) {
                    return true;
                } else if (other instanceof SubscriberMethod) {
                    checkMethodString();
                    SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
                    otherSubscriberMethod.checkMethodString();
                    // Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
                    return methodString.equals(otherSubscriberMethod.methodString);
                } else {
                    return false;
                }
            }
            private synchronized void checkMethodString() {
                if (methodString == null) {
                    // Method.toString has more overhead, just take relevant parts of the method
                    StringBuilder builder = new StringBuilder(64);
                    builder.append(method.getDeclaringClass().getName());
                    builder.append('#').append(method.getName());
                    builder.append('(').append(eventType.getName());
                    methodString = builder.toString();
                }
            }
            @Override
            public int hashCode() {
                return method.hashCode();
            }
            }
            

SubscribeMethod 携带了Method函数原型,还有就是我们在注解类里面提供的所有信息。还有一个Class<?>类型的EventType是指我们的事件类所对应的Class,其余的方法都是为了比较和判断是否相等来做的,equal/checkMethodString都是各种的拼字串来进行存储和判断。

下面我们来看register里面调用的这段subscribe,这段非常的重要涉及了EventBus运行时处理的绝大多数部分,还有就是粘性事件的分发。这段使用了大量的JDK的反射包的API,本身注释也提醒我们了这段代码需要加锁,毕竟里面这一堆并发容器。所以我们最好先明确这段里面用的并发容器到底都是什么,这段代码才好继续看的下去。

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
        private final Map<Object, List<Class<?>>> typesBySubscriber;
        private final Map<Class<?>, Object> stickyEvents;
        

主要的有这几个:

  1. 第一个Map存储的Key是Class类型,Value是一个并发的ArrayList里面存的是对订阅者和订阅函数的一种绑定类Subscription从名字上也能看出Key是Event的Class对象。
  2. 第二个存储的是订阅者(Activity什么的啊)和Event类型的List。
  3. 第三个Map存储的是粘性事件,Key是Event类型,Value是真实存在的StickyEvent对象。

知道这三个都是什么之后,这段代码就好看了。我们来看前一部分。

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

这段写的虽然有点乱套,但实际上写的挺简单的,而且一堆堆的O(n)遍历,性能也就那样(?)。

首先这里面出现了Subscription:

final class Subscription {
            final Object subscriber;
            final SubscriberMethod subscriberMethod;
            /**
             * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
             * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
             */
            volatile boolean active;
            Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
                this.subscriber = subscriber;
                this.subscriberMethod = subscriberMethod;
                active = true;
            }
            @Override
            public boolean equals(Object other) {
                if (other instanceof Subscription) {
                    Subscription otherSubscription = (Subscription) other;
                    return subscriber == otherSubscription.subscriber
                            && subscriberMethod.equals(otherSubscription.subscriberMethod);
                } else {
                    return false;
                }
            }
            @Override
            public int hashCode() {
                return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
            }
            }
            

我们发现了这是订阅者和订阅方法类的一个契约关系类。

所以说上面subscribe函数主要做了,

  • 创建了订阅者和方法类的绑定,然后存进了subscriptionsByEventType
  • 对每个类型重新排列了一次优先级
  • typesBySubscriber添加了对应的类型

然后我们可以看一下这个函数的下一半,我们会惊奇地发现,StickyEvent的发送时机居然是在register的时候:

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

这时候轮了一遍所有的粘性事件。isAssignableFrom类似于使用在Class之间的instance of 就是判断两个类是否有相同的接口关系,也就是说有继承和实现关系的事件类,都会被判断处理。

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, Looper.getMainLooper() == Looper.myLooper());
              }
          }
          
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 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进行了处理,同一线程的直接依赖Java的反射invoke执行了,各种不可以的情况,比如说发到主线程但还没在主线程的时候,都是用队列进行发送到对应线程。

接下来我们看看这里面在各线程之间的发送是怎么实现的。

消息转换线程

我们发现在Subscription和event入队的时候我们把他们封装成了一个PendingPost类:

// HandlePoster    
        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");
                        }
                    }
                }
            }
            

然后才进行的入队和发送,这个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);
                    }
                }
            }
            }
            

这里的设计其实挺不错的,一个静态的回收池,初始化靠一个静态方法,优先使用被回收的对象,实现和Message其实很像。另一个release方法就是把用完的对象回收起来。

PendingPostQueue 就是一个PendingPost的队列,里面的操作基本上就是入队出队之类的,有点特殊的是入队和出队都有一把锁。

接着这个队列被用在了好几个Poster类中,实现了向各个线程的消息转换,首先我们来看向主线程发送数据的:

HandlePoster

final class HandlerPoster extends Handler {
                private final PendingPostQueue queue;
                private final int maxMillisInsideHandleMessage;
                private final EventBus eventBus;
                private boolean handlerActive;
                HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
                    super(looper);
                    this.eventBus = eventBus;
                    this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
                    queue = new PendingPostQueue();
                }
                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) {
                                if (!sendMessage(obtainMessage())) {
                                    throw new EventBusException("Could not send handler message");
                                }
                                rescheduled = true;
                                return;
                            }
                        }
                    } finally {
                        handlerActive = rescheduled;
                    }
                }
                }
                

HandlePoster 继承自 Handler 再加上初始化的时候传进去的是Looper.getMainThread();所以能向主线程发送消息。每次入队之后都会发送一条空消息去通知handleMessage函数处理队列数据,使用handlerActive作为控制标记位。handleMessage是个死循环两段的if判断用来处理多线程的情况,invokeSubscriber的方式和之前类似。之后就是有一个阀值,当时间超过10ms的时候就会发一个消息重入,并且退出这次循环,这是防止时间太长阻塞主线程。

BackgroundPoster

final class BackgroundPoster implements Runnable {
                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) {
                            Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
                        }
                    } finally {
                        executorRunning = false;
                    }
                }
                }
                

BackgroundPoster 自身是一个Runnable ,入队之后就调用EventBus携带的一个线程池进行运行,同样也是一个死循环,用了一个生产者 vs 消费者模式 进行了有限等待,这1000ms内入队的消息都会被弹出处理。

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

PendingPostQueue的poll(int)方法对队列为空的情况进行了等待,唤醒则出现在enqueue:

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(); // 在这进行了唤醒
            }
            

AsyncPoster

如果说Background尚且能保证在同一个线程内完成,AsyncPoster就完全进行了异步操作。

class AsyncPoster implements Runnable {
            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);
            }
            }
            

这里面基本上什么都不控制,直接就来一个运行一次,也不会有什么问题。。。

到这为止我们不但知道了方法是怎么注册和绑定的,我们甚至还知道了粘性事件是怎么发送的了,接着我们来看方法查找和普通事件的发送是怎么进行的。

方法查找

// package org.greenrobot.eventbus.meta;
            /** Base class for generated index classes created by annotation processing. */
            public interface SubscriberInfo {
                // 获取订阅的类
                Class<?> getSubscriberClass();
               // 所有的method
                SubscriberMethod[] getSubscriberMethods();
              // 获取父类的info
                SubscriberInfo getSuperSubscriberInfo();
                // 是否检查父类
                boolean shouldCheckSuperclass();
                }
                

SubscriberInfo 描述了能通过注解类生成的Index的方法(具体功能我加了主食)。

/**
         * Interface for generated indexes.
         */
         public interface SubscriberInfoIndex {
            SubscriberInfo getSubscriberInfo(Class<?> subscriberClass);
            }
            

这个接口是查找info的。

另外可以说这其中的SubscriberMethodInfo存储着SubscriberMethod所需的元信息:

public class SubscriberMethodInfo {
            final String methodName;
            final ThreadMode threadMode;
            final Class<?> eventType;
            final int priority;
            final boolean sticky;
          ...
          

AbstractSubscriberInfo是一个抽象类,主要负责从Info创建出Method,又是一个反射:

protected SubscriberMethod createSubscriberMethod(String methodName, Class<?> eventType, ThreadMode threadMode,
                                                          int priority, boolean sticky) {
            try {
                Method method = subscriberClass.getDeclaredMethod(methodName, eventType);
                return new SubscriberMethod(method, eventType, threadMode, priority, sticky);
            } catch (NoSuchMethodException e) {
                throw new EventBusException("Could not find subscriber method in " + subscriberClass +
                        ". Maybe a missing ProGuard rule?", e);
            }
            }
            

另外还有一个SimpleSubscriberInfo作为他的子类。

接下来的SubscriberMethodFinder也非常重要运行时的方法查找都来自这里:

刚才我们在EventBus.register(...)中调用了这个函数:

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

其中的METHOD_CACHE是对每个类方法进行缓存,防止多次查找,毕竟运行时查找还是个复杂的操作,根据是否忽略生成Index。

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

findUsingReflectionInSingleClass对反射类进行了处理,这里面通过掩模运算检查了访问权限, 检查了参数个数。

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)) {
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    // Put any non-Method object to "consume" the existing Method
                    anyMethodByEventType.put(eventType, this);
                }
                return checkAddWithMethodSignature(method, eventType);
            }
            }
            

其中的checkAdd检查了类型和方法签名,每次轮转完成之后都会进行一次findState.moveToSuperclass();对父类进行处理。

使用索引

因为反射所使用的运行时查找速度缓慢,所以我们也经常会通过apt使用已经创建好的Index。

刚才另一个分支的findUsingInfo就是使用已有的Index:

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

这段非常简单,几乎就是刚才的验证而已,如果没拿到数据的话,还会进行正常的反射查找。

// EventBusAnnotationProcessor 负责生成注解路由表
           private void createInfoIndexFile(String index) {
               BufferedWriter writer = null;
               try {
                   JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index);
                   int period = index.lastIndexOf('.');
                   String myPackage = period > 0 ? index.substring(0, period) : null;
                   String clazz = index.substring(period + 1);
                   writer = new BufferedWriter(sourceFile.openWriter());
                   if (myPackage != null) {
                       writer.write("package " + myPackage + ";\n\n");
                   }
                   writer.write("import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;\n");
                   writer.write("import org.greenrobot.eventbus.meta.SubscriberMethodInfo;\n");
                   writer.write("import org.greenrobot.eventbus.meta.SubscriberInfo;\n");
                   writer.write("import org.greenrobot.eventbus.meta.SubscriberInfoIndex;\n\n");
                   writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n");
                   writer.write("import java.util.HashMap;\n");
                   writer.write("import java.util.Map;\n\n");
                   writer.write("/** This class is generated by EventBus, do not edit. */\n");
                   writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n");
                   writer.write("    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;\n\n");
                   writer.write("    static {\n");
                   writer.write("        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();\n\n");
                   writeIndexLines(writer, myPackage);
                   writer.write("    }\n\n");
                   writer.write("    private static void putIndex(SubscriberInfo info) {\n");
                   writer.write("        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);\n");
                   writer.write("    }\n\n");
                   writer.write("    @Override\n");
                   writer.write("    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {\n");
                   writer.write("        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);\n");
                   writer.write("        if (info != null) {\n");
                   writer.write("            return info;\n");
                   writer.write("        } else {\n");
                   writer.write("            return null;\n");
                   writer.write("        }\n");
                   writer.write("    }\n");
                   writer.write("}\n");
               } catch (IOException e) {
                   throw new RuntimeException("Could not write source for " + index, e);
               } finally {
                   if (writer != null) {
                       try {
                           writer.close();
                       } catch (IOException e) {
                           //Silent
                       }
                   }
               }
           }
           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");
                   }
               }
           }
           

有了这两个方法之后我们就知道,平常的index就是通过这种方式拼接出来的。

Post消息

/** Posts the given event to the event bus. */
            public void post(Object event) {
                PostingThreadState postingState = currentPostingThreadState.get();
                List<Object> eventQueue = postingState.eventQueue;
                eventQueue.add(event);
                if (!postingState.isPosting) {
                    postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
                    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;
                    }
                }
                }
                

PostingThreadState是一个存储在ThreadLocal中的对象,包含有以下各种内容,线程信息,是否是主线程,是否取消,还有一个相应的事件队列。

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
              Class<?> eventClass = event.getClass();
              boolean subscriptionFound = false;
              if (eventInheritance) {
                    /** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */
                  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) {
                      Log.d(TAG, "No subscribers registered for event " + eventClass);
                  }
                  if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                          eventClass != SubscriberExceptionEvent.class) {
                      // 无订阅者的处理
                      post(new NoSubscriberEvent(this, event));
                  }
              }
          }
          

之后:

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

之后对所有的订阅类的所有订阅者都发送一次数据,发送数据方法和上文相同。

发送粘性数据就是拿锁然后保存到队列中去,这样就可以在重新发送:

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

因为我们无法确定什么时候粘性事件应该停止继续传播,这取决于我们应用的需要,所以我们应当手动remove掉Sticky Event :

// 系统提供了如下方法
         public <T> T removeStickyEvent(Class<T> eventType) {
                synchronized (stickyEvents) {
                    return eventType.cast(stickyEvents.remove(eventType));
                }
            }
            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;
                    }
                }
            }
            public void removeAllStickyEvents() {
                synchronized (stickyEvents) {
                    stickyEvents.clear();
                }
            }
            

至此我们就分析完了EventBus的基本上所有的代码(处理util包下的错误日志),EventBus本身的实现并不复杂,使用运行时的反射技巧也很简单,单纯的使用注解类可能会拖慢速度,但是通过apt生成的静态表把速降提升到了一个新的高度,apt的生成大家也看到了并不是很复杂,几乎就是类型检查和拼接字串,不过想法决定了EventBus仍然是一个优秀的开源库,希望我们在使用的同时,仍能对实现原理有所了解。