EventBus3.0源码分析(上)

概述

关于EventBus3.x的用法,本文不再赘述,只分析其实现原理,官方的流程图:


上图是EventBus基于观察者模式的事件发布流程的高度概括,经过下文的源码分析后,再来体会该流程会比较清晰。

订阅流程

需要订阅事件的对象首先需要进行注册,比如Activity中:

EventBus.getDefault().register(activity);

看看EventBus这个类中做了什么:

 /** Convenience singleton for apps using a process-wide EventBus instance. */
    /** 典型的单例模式*/
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

很明显是典型的单例模式,那么看看EventBus的构造方法:

 /**传入建造者进行参数构建*/
    EventBus(EventBusBuilder builder) {
        //eventType作为key,Subscription为value的map集合
        subscriptionsByEventType = new HashMap<>();
        //key为订阅对象,value为该对象中所有的订阅event类型的map集合
        typesBySubscriber = new HashMap<>();
        //黏性事件map集合
        stickyEvents = new ConcurrentHashMap<>();
        //主线程的事件处理器
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        //后台线程的事件处理器
        backgroundPoster = new BackgroundPoster(this);
        //异步的事件处理器
        asyncPoster = new AsyncPoster(this);
        //注解处理器生成的索引数量,如果没用注解处理器那么为0
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        //订阅方法的查找封装类,主要用于查找订阅对象中的订阅方法
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        //事件继承 默认true
        eventInheritance = builder.eventInheritance;
        //线程池
        executorService = builder.executorService;
    }

因为参数很多所以使用了建造者模式,这也是许多开源框架经常使用的模式,对这些参数暂时不懂没有关系,继续看下面:

    /**
     * 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.
     * 给事件的订阅者进行注册。订阅者一旦不再接受事件后,必须调用{@link #unregister(Object)}这个方法来进行
     * 取消订阅。
     * 订阅者的事件处理方法必须用{@link Subscribe}进行注解,该注解也允许配置 {@link ThreadMode}等属性
     */
    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();//获取订阅者对象的Class
        //根据订阅者对象的Class来获取订阅者的事件处理方法的list集合
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
       //循环对订阅者的方法进行注册
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

这里

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

subscriberMethodFinder 对象主要封装了查找订阅者信息的一系列方法
SubscriberMethod主要封装了订阅方法的信息,比较简单:

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

接下来看看subscriberMethodFinder中的方法:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        //首先从缓存中获取保存的订阅者方法list集合
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {//如果之前缓存过,就直接返回
            return subscriberMethods;
        }
        //ignoreGeneratedIndex 是否忽略由注解处理器生成的索引, 默认false
        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 {
            //将key为订阅者Class,value为subscriberMethods 放入缓存,并返回
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

该方法主要是从缓存中查找订阅者的订阅信息,如果没有则通过findUsingInfo(subscriberClass)方法查找:

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        //FindState 封装了订阅对象信息和订阅方法检测校验的类,并可以复用
        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);
    }

这里findState对象其实封装了一些订阅信息和查找方法,简单看下:

static class FindState {
        //SubscriberMethod 订阅方法的集合
        final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
        //存储事件类型的集合
        final Map<Class, Object> anyMethodByEventType = new HashMap<>();
        //方法签名和订阅类的集合
        final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
        final StringBuilder methodKeyBuilder = new StringBuilder(128);

        Class<?> subscriberClass;
        Class<?> clazz;
        boolean skipSuperClasses;
        SubscriberInfo subscriberInfo;
...省略
}

看看prepareFindState方法,主要是获取一个FindState对象:

private FindState prepareFindState() {
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                FindState state = FIND_STATE_POOL[i];
                //从FindState 的缓存数组中取出一个对象进行复用
                if (state != null) {
                    FIND_STATE_POOL[i] = null;
                    return state;
                }
            }
        }//如果没有就直接new一个
        return new FindState();
    }

继续看看initForSubscriber方法,主要是进行了一些初始化:

static class FindState {
...以上省略
        void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false;
            subscriberInfo = null;
        }
...以下省略
}

之后进入while循环,然后先说不使用注解处理器的情况,会调用findUsingReflectionInSingleClass(findState);:

 private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // This is faster than getMethods, especially when subscribers are fat classes like Activities
            //注意 getDeclaredMethods 只获取当前类的方法,而不获取父类继承的方法,因此比getMethods方法速度更快
            //比如Activity本身就有大量方法,那么Activity的子类无疑使用getDeclaredMethods更好
            // 获取订阅对象所有的Method对象数组
            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();
            //判断方法是否为public,对于方法必须为public的设计,应该是为了提高查找速度,否则需要挨个判断方法注解
            //否则报异常
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                //获取方法的参数类型Class数组
                Class<?>[] parameterTypes = method.getParameterTypes();
                //参数只能是一个,否则报错
                if (parameterTypes.length == 1) {
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    //判断是否是Subscribe注解类型
                    if (subscribeAnnotation != null) {
                        Class<?> eventType = parameterTypes[0];
                        //checkAdd方法主要是检测事件类型在同一个对象或者父类中是否重复注册过
                        if (findState.checkAdd(method, eventType)) {
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            //然后将订阅方法的信息封装为SubscriberMethod,并添加到findState.subscriberMethods
                            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");
            }
        }
    }

方法其实比较清晰,主要是根据反射和注解获取方法上的订阅信息并进行封装操作,然后比较关键的检测操作findState.checkAdd(method, eventType)

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.
          //2层检测,首先检测eventType,再进行完整的签名检测,一般来讲订阅对象不会重复定义监听同样的event类型的方法
          //但是如果有多个同样event类的订阅方法,那么也是合法的
          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
                  //如果之前有相同event类型的方法存在,那么为了兼容同一个类的多个同样event的方法
                  //放入一个不是Method类型的对象,这样根据不同的判断就能区别是父类还是多方法
                  anyMethodByEventType.put(eventType, this);
              }
              return checkAddWithMethodSignature(method, eventType);
          }
      }

private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
          methodKeyBuilder.setLength(0);
          methodKeyBuilder.append(method.getName());
          methodKeyBuilder.append('>').append(eventType.getName());
          //用方法名和event名称组成key
          String methodKey = methodKeyBuilder.toString();
          //获取订阅方法所在的Class
          Class<?> methodClass = method.getDeclaringClass();
          //根据key,添加methodClass到缓存,并且得到methodClassOld
          Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
          //如果methodClassOld不存在或者是methodClass自身或methodClass的父类,那么返回true,因为继承关系会继承事件订阅
          //如果子类有重写了继承的订阅方法,那么只会保留子类的订阅方法
          if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
              // Only add if not already found in a sub class
              return true;
          } else {
              // Revert the put, old class is further down the class hierarchy
              //检测到父类注册后,否则还是将methodClassOld放回缓存,因为子类重写了,所以返回false,不会再父类方法注册
              subscriberClassByMethodKey.put(methodKey, methodClassOld);
              return false;
          }
      }

该方法主要检测订阅方法的合法性,个人的理解是一种情况是用一个类中注册了多个同样event类型的方法,这种情况是允许的,另一种是子类重写父类的继承方法,如果是这样的情况那只会保留子类的订阅方法,仔细体会这里的写法。
检测完成之后再返回到findUsingReflectionInSingleClass(FindState findState)方法继续看:

ThreadMode threadMode = subscribeAnnotation.threadMode();
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));

很好理解了,就是将订阅方法封装到findState对象中了,后面是要取出的。
这之后再返回到findUsingInfo(Class<?> subscriberClass)方法中:

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        //FindState 封装了订阅对象信息和订阅方法检测校验的类,并可以复用
        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);
    }

此时还是处在while循环中,下一步findState.moveToSuperclass();再进入父类进行循环,直到结束,之后调用:

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
        List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
        findState.recycle();
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                if (FIND_STATE_POOL[i] == null) {
                    FIND_STATE_POOL[i] = findState;
                    break;
                }
            }
        }
        return subscriberMethods;
    }

该方法的作用是将findState封装的subscriberMethods集合返回,并将findState对象清空,并放入FIND_STATE_POOL缓存数组之中,方便下次使用,个人理解这里是为了优化性能,减少了重复创建对象的开销。
之后返回到findSubscriberMethods(Class<?> subscriberClass)方法:

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

         ...上面代码省略
        //如果找不到注解方法抛出异常
        if (subscriberMethods.isEmpty()) {
            throw new EventBusException("Subscriber " + subscriberClass
                    + " and its super classes have no public methods with the @Subscribe annotation");
        } else {
            //将key为订阅者Class,value为subscriberMethods 放入缓存,并返回
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

这里METHOD_CACHE是ConcurrentHashMap集合,key是订阅对象的Class,value是该对象中所有的订阅方法集合,下次查找的时候如果存在了就可以直接从缓存中取出了。
之后再返回到:

    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();//获取订阅者对象的Class
        //根据订阅者对象的Class来获取订阅者的事件处理方法的list集合
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
       //循环对订阅者的方法进行注册
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

进入for循环,逐个遍历订阅者和订阅方法,看看subscribe(subscriber, subscriberMethod)方法:

    // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
        //Subscription 就是订阅对象和订阅方法的再次封装
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        //subscriptionsByEventType 就是eventType作为key,Subscription为value的map集合缓存,这里是取出之前的保存Subscription类型的List
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        //subscriptions 是Null就new一个,subscriptionsByEventType并将eventType,subscriptions保存起来
        //但subscriptions此时还没有任何Subscription对象
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {//如果subscriptions已经包含了再次封装的Subscription,那么抛出异常提示
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }

        //这里会根据event的优先级来插入到subscriptions中,如果优先级相同就插入到最后
        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;
            }
        }

        //typesBySubscriber 是key为订阅对象,value为该对象中所有的event的map集合
        //该集合作用是后续取消订阅的时候,方便移除订阅对象
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        //subscribedEvents为null的话就new一个,然后typesBySubscriber将订阅对象和event加入进来
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        //subscribedEvents 将eventType加入进来
        subscribedEvents.add(eventType);
        //判断是不是黏性事件
        if (subscriberMethod.sticky) {
            //eventInheritance 事件继承,默认true
            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);
            }
        }
    }

该方法并不难理解,Subscription就是Object subscriber, SubscriberMethod subscriberMethod这两个对象的再封装,subscriptionsByEventType就是eventType作为key,Subscription为value的map集合缓存,设计用意就是根据事件类型找出所有的订阅者信息,这样当事件发布的时候能够方便给所有的订阅者进行方法的调用,subscribedEvents就是以订阅者subscriber为key,事件class为value的map集合缓存,在取消注册的时候可以方便进行订阅事件的删除。
然后判断是不是黏性事件,如果是黏性事件,那么首先会判断是否支持事件继承,默认true,意思就是如果订阅方法中的事件类如果实现了某些接口,那么其他实现了这些接口的订阅事件类或者是订阅事件类的父类同样会接收到事件信息,检测通过后就会直接发送事件,这个在post流程中可以体现出来,后面再进行分析,那么注册流程基本就是这样。

发布事件流程

再来看看发布流程,先看发布方法post(Object event)

/** Posts the given event to the event bus. */
    public void post(Object event) {
       //首先获取当前线程保存的事件队列
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
       //将事件加入队列
        eventQueue.add(event);
        //如果没有在发布状态
        if (!postingState.isPosting) {
       //利用当前线程的Looper是否是主线程的Looper来判断当前线程是否为主线程
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
           //发布状态为true
            postingState.isPosting = true;
          //判断有没有取消发布
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                while (!eventQueue.isEmpty()) {
                    //循环取出当前队列的所有事件进行事件发布
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

该方法的主要作用就是将发布的事件加入队列然后,再将当前线程保存的事件队列全部发布出去,看下currentPostingThreadState

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

很明显是保存了PostingThreadState的ThreadLocal对象,利用了ThreadLocal的线程特性来获取当前线程的PostingThreadState对象,关于ThreadLocal的讨论网上已经很多,个人也曾做过相关分析Android ThreadLocal及InheritableThreadLocal分析,如有需要可参考。
这个PostingThreadState对象就是封装了当前线程的事件队列和发布状态等信息:

    /** For ThreadLocal, much faster to set (and get multiple values). */
    final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<Object>();
        boolean isPosting;
        boolean isMainThread;
        Subscription subscription;
        Object event;
        boolean canceled;
    }

明白了这些,之后回到post方法中的while循环方法postSingleEvent(eventQueue.remove(0), postingState):

   private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        //默认true,支持事件继承
        if (eventInheritance) {
            //循环找出事件类的所有接口类
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                //开始循环发布事件
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        //如果没有找到订阅者那么做出提示,并发布一个NoSubscriberEvent事件
        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));
            }
        }
    }

该方法主要是找出当前事件类的所有接口类,并进行循环发布事件,如果没有订阅者,那么发布一个默认的NoSubscriberEvent事件。先看看是如何查找事件类的所有接口的lookupAllEventTypes(eventClass)

 /** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */
    private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
        synchronized (eventTypesCache) {
            //eventTypesCache 就是以事件类为key,以对应的接口类集合为value的map缓存
            List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
            if (eventTypes == null) {
                eventTypes = new ArrayList<>();
                Class<?> clazz = eventClass;
                while (clazz != null) {
                    //先加入当前的 事件类,然后再添加接口类
                    eventTypes.add(clazz);
                    addInterfaces(eventTypes, clazz.getInterfaces());
                   //再循环父类
                    clazz = clazz.getSuperclass();
                }
                eventTypesCache.put(eventClass, eventTypes);
            }
            return eventTypes;
        }
    }

这里clazz.getInterfaces()可以找出所有对应的接口集合,看看addInterfaces(eventTypes, clazz.getInterfaces())方法:

   /** Recurses through super interfaces. */
    static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {
        for (Class<?> interfaceClass : interfaces) {
            if (!eventTypes.contains(interfaceClass)) {
                eventTypes.add(interfaceClass);
                addInterfaces(eventTypes, interfaceClass.getInterfaces());
            }
        }
    }

该方法递归调用获取到所有的接口类并添加到缓存,看完这里继续返回到post方法中的subscriptionFound = postSingleEventForEventType(event, postingState, eventClass),看看该方法中做了什么:

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            //subscriptionsByEventType缓存中根据事件类取出订阅者集合
            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;
    }

该方法非常简单,就是根据事件类取出之前缓存的订阅着集合然后进行事件的发布,看看postToSubscription(subscription, event, postingState.isMainThread)方法:

    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
         //根据不同的订阅线程,进行不通的处理
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                //post行程的话就直接发布
                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);
        }
    }

这个方法就是根据不通的线程属性做相应的处理,先看下最终的调用方法:

    void invokeSubscriber(Subscription subscription, Object event) {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }

就是利用反射调用方法了,很简单,然后看下黏性方法的调用过程,之后我们分析下几个不同的Poster。
发送黏性事件的方法:

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

非常简单,首先加入stickyEvents这个黏性事件的map集合,然后再调用普通的post方法,这样保证先注册该事件的会被调用,然后再有相关事件被注册的时候,就回到register(Object subscriber)中,从stickyEvents中找到相关的事件消息再直接调用,保证后注册的的方法也能被立即调用到。
明白了这些我们再看看不同的poster吧,这里看看HandlerPoster为例,分析之前先看看相关的封装对象:

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;
    }
    //从缓存池中取出对象,如果缓冲池没有,则new一个返回
    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);
            }
        }
    }

}

这个PendingPost对象,很明显是链表设计,next指向的就是下一个PendingPost对象,其中的几个方法也简单易懂,并设计了缓存池实现复用,考虑细致。
再看看链表的设计:

final class PendingPostQueue {
    private PendingPost head;//链表头对象
    private PendingPost tail;//链表尾对象
    //对象入队操作
    synchronized void enqueue(PendingPost pendingPost) {
        if (pendingPost == null) {
            throw new NullPointerException("null cannot be enqueued");
        }
         //如果尾部对象不为空,那么将尾部next对象指向当前对象
         //然后尾部对象再指向当前对象,这样就将对象插入到尾部
        if (tail != null) {
            tail.next = pendingPost;
            tail = pendingPost;
        } else if (head == null) {
            //如果头部对象为空,那么头尾均为当前对象
            head = tail = pendingPost;
        } else {
            throw new IllegalStateException("Head present, but no tail");
        }
         //释放锁
        notifyAll();
    }
     //取出一个对象,从头部取
    synchronized PendingPost poll() {
        PendingPost pendingPost = head;
        if (head != null) {
            //每取出一个就将头部的引用指向下个对象,完成出队
            head = head.next;
            if (head == null) {//如果为空了,那么队列为空
                tail = null;
            }
        }
        return pendingPost;
    }

    //可以让线程等待一定时间再取对象
    synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
        if (head == null) {
            wait(maxMillisToWait);
        }
        return poll();
    }

}

该对象主要实现了单链表,入队出队操作也比较简单明了。
弄明白了这个链表结构,再看看HandlerPoster就比较清晰了:

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) {
                    //如果为null就进行再次同步检测
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            //如果还是空,那么结束循环
                            handlerActive = false;
                            return;
                        }
                    }
                }
                //事件不为空则进行事件的调用
                eventBus.invokeSubscriber(pendingPost);
               //这里如果while循环进行的时间超过规定时间,那么会退出下,同时再发送
               //发送个消息,这样应该是防止长时间阻塞主线程,考虑到了事件过多的情况
                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;
        }
    }
}

通过上面的注释可以知道,HandlerPoster会把消息入队并在主线程处理,handlerActive用来控制是否正在处理消息的状态,防止发送过快,并细致地考虑到主线程阻塞的可能性,这样就完成了消息的处理。
另外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) {
                    //这里设定了一个等待时间,如果队列为null了,那么等待1000ms
                    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;
        }
    }

}

代码和HandlerPoster比较类似,实现了Runnable接口,加入了一个等待时间,如果队列为空了等待1000ms后已经取不到对象,那么久真正退出了,也就是说尽量在同一个后台线程处理完所有的消息。
看看``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);
    }

}

非常简单,每次入队都会在新的线程执行一次,而不是进行while循环,这样总是在新的线程进行消息的处理,并且不能保证调用顺序,这三个poster的区别可以再慢慢体会。

取消订阅流程

public synchronized void unregister(Object subscriber) {
    //首先根据注册类找到所有的注册事件类型
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        //遍历事件类型,从事件对应的subscriptions集合中,移除订阅者
        for (Class<?> eventType : subscribedTypes) {
            unsubscribeByEventType(subscriber, eventType);
        }
        //然后移除订阅者所有对应的事件类
        typesBySubscriber.remove(subscriber);
    } else {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
    //根据事件类型找到所有的订阅者信息
    List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions != null) {
        int size = subscriptions.size();
        for (int i = 0; i < size; i++) {
            Subscription subscription = subscriptions.get(i);
            //如果找到了订阅者,那么移除
            if (subscription.subscriber == subscriber) {
                subscription.active = false;
                subscriptions.remove(i);
                i--;
                size--;
            }
        }
    }
}

取消注册流程较为简单,主要是移除订阅者自身和所对应的事件信息。
以上就是在不使用注解处理器的情况下的事件发布和调用流程,下篇来分析下使用注解处理器的执行过程。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容