EventBus源码分析

相信大家都有在项目中使用过EventBus。EventBus是一个性能高效的基于观察者模式的事件发布与订阅框架。借助EventBus,我们只需几行代码便能实现组件之间、线程之间的通信,达到解耦的目的。

EventBus源码分析_第1张图片

这篇文章不对EventBus的使用进行介绍,而是格物致知,探究EventBus的源码。

1. 入口

一般使用时是通过EventBus.getDefault()来调用注册、发布与注销的方法。因此,我们从getDefault()这个入口开始分析。

public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
        if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

这里使用了双重检验锁(单例模式的一种实现方式)的来保证EventBus实例的唯一性。接着进入构造函数看看:

public EventBus() {
    this(DEFAULT_BUILDER);
}

EventBus(EventBusBuilder builder) {
    subscriptionsByEventType = new HashMap<>();
    typesBySubscriber = new HashMap<>();
    stickyEvents = new ConcurrentHashMap<>();
    mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
    backgroundPoster = new BackgroundPoster(this);
    asyncPoster = new AsyncPoster(this);
    indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
            builder.strictMethodVerification, builder.ignoreGeneratedIndex);
    logSubscriberExceptions = builder.logSubscriberExceptions;
    logNoSubscriberMessages = builder.logNoSubscriberMessages;
    sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
    sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
    throwSubscriberException = builder.throwSubscriberException;
    eventInheritance = builder.eventInheritance;
    executorService = builder.executorService;
}

在无参构造函数内调用了带有EventBusBuilder参数的构造函数,这里使用了Builder模式,将参数的构建过程交给EventBusBuilder。Builder模式是一种常见的设计模式,例如在sdk开发中参数过多时,将参数的构建过程交给Param:

Param param = Param.instance().param1(value1).param2(value2)......;
SDK.init(context, param);

在EventBus的构造函数内,进行了初始化的工作。这些参数的含义对后面的分析很重要,这里简单介绍下这些属性的作用:

  • subscriptionsByEventType:以EventType(Event对象的Class类)为key,Subscription(订阅者以及一个订阅方法)数组为value。根据EventType可以查询到相应的订阅者及订阅方法。
  • typesBySubscriber:以Subscriber(订阅者,即调用register方法的类)为key,EventType数组为value。根据订阅者可以查询到它订阅的所有事件。
  • stickyEvents:以EventType为key,Event为value。用来保存粘性事件。
  • mainThreadPoster、backgroundPoster、asyncPoster:EventBus支持四种ThreadMode,POSTING、MAIN、BACKGROUND、ASYNC。POSTING直接在发布事件的线程处理,这三个poster分别用来支持剩下的三种Mode。
  • indexCount:索引类数目,索引类指的是EventBus利用注解处理器生成的保存订阅者信息的类。如果lib中也用了EventBus,就可能存在多个索引类。
  • subscriberMethodFinder:查找及缓存订阅者信息的类。
  • logSubscriberExceptions:当事件处理过程发生异常时是否打印日志,默认为true。
  • logNoSubscriberMessages:当事件没有订阅者订阅时是否打印日志,默认为true。
  • sendSubscriberExceptionEvent:当事件处理过程发生异常时是否发送SubscriberExceptionEvent,默认为true。当为true时,订阅者可以订阅SubscriberExceptionEvent事件。
  • sendNoSubscriberEvent:当事件没有订阅者订阅时是否发送NoSubscriberEvent,默认为true。当为true时,订阅者可以订阅NoSubscriberEvent事件。
  • throwSubscriberException:当事件处理过程发生异常时是否抛出EventBusException,默认为false。
  • eventInheritance:是否支持事件继承,默认为true。当为true时,post一个事件A时,若A是B的子类或者A实现了接口B,订阅B的订阅者也能接收到事件。
  • executorService:线程池,负责线程调度。

因此,通过EventBus.getDefault()我们就可以得到一个默认配置的EventBus单例,也支持通过EventBusBuilder来自定义配置。

2. 注册订阅者

接下来看下通过EventBus.getDefault().register()注册订阅者时发生了什么?

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

当注册订阅者时,会通过SubscriberMethodFinder的findSubscriberMethods来获取SubscriberMethod数组,SubscriberMethod保存了订阅方法的信息。打开SubscriberMethod可以发现一点,在SubscriberMethod有Method对象以及methodString,其实methodString也是通过method反射获取到的,这里利用一个变量保存起来,避免每次都通过反射获取降低性能。类似的,在EventBus其实还有很多这种细微的优化。

得到SubscriberMethod数组后,依次进行注册。先看看获取到SubscriberMethod数组后,是如何通过subscribe进行订阅的:

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    Class eventType = subscriberMethod.eventType;
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    CopyOnWriteArrayList 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> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);

    // 粘性事件处理, 将在第五小节分析
}

3-30行容易理解,主要是将EventType -> Subscription的映射加入到subscriptionsByEventType,将Subscriber -> EventType的映射与加入到typesBySubscriber中。subscriptionsByEventType里每个事件的Subscription是按照优先级排序的,优先级高的订阅者可以中途通过cancelEventDelivery来拦截。

31行后面部分的代码部分涉及到粘性事件,将在第五小节中分析。

回过头看看findSubscriberMethods是如何获取到SubscriberMethod数组的:

List findSubscriberMethods(Class subscriberClass) {
    List 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;
    }
}

在findSubscriberMethods方法内,如果METHOD_CACHE中没有的话才进行查找的工作。然后根据ignoreGeneratedIndex判断查找的方式。

EventBus3.0里使用了一项“秘密武器”使得效率大大提升,这个武器其实就是之前文章里提过的注解处理器。如果ignoreGeneratedIndex是false的话,就采用注解处理器生成索引类去获取SubscriberMethod;否则采用反射的方式。

  • butterknife源码分析:如何处理注解—反射与注解处理器
    http://blog.csdn.net/u012933743/article/details/54972050

2.1. 索引获取SubscriberMethod

ignoreGeneratedIndex默认为false,因此会调用findUsingInfo:

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

在findUsingInfo开始时,会通过prepareFindState获取FindState对象,FindState保存了在查找SubscriberMethod时的一些属性,并封装了检验合法性的方法。prepareFindState里从对象池FIND_STATE_POOL里取一个已经创建好的对象,然后通过initForSubscriber去初始化。这也是一个细微的优化,利用对象池避免了频繁的对象创建。

private FindState prepareFindState() {
    synchronized (FIND_STATE_POOL) {
        for (int i = 0; i < POOL_SIZE; i++) {
            FindState state = FIND_STATE_POOL[i];
            if (state != null) {
                FIND_STATE_POOL[i] = null;
                return state;
            }
        }
    }
    return new FindState();
}

得到FindState后,先通过getSubscriberInfo获取订阅者信息SubscriberInfo:

private SubscriberInfo getSubscriberInfo(FindState findState) {
    if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
        SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
        if (findState.clazz == superclassInfo.getSubscriberClass()) {
            return superclassInfo;
        }
    }
    if (subscriberInfoIndexes != null) {
        for (SubscriberInfoIndex index : subscriberInfoIndexes) {
            SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
            if (info != null) {
                return info;
            }
        }
    }
    return null;
}

在getSubscriberInfo方法内,第一个判断其实进不去,因为findState.subscriberInfo.getSuperSubscriberInfo()始终返回null。然后直接SubscriberInfoIndex的getSubscriberInfo来获得订阅者信息SubscriberInfo。SubscriberInfoIndex就是采用注解处理器生成的索引类,包含了订阅者及其订阅方法的信息。

回到刚刚findUsingInfo的方法,得到SubscriberInfo后,获取订阅者内的SubscriberMethod数组。对于每个SubscriberMethod,调用FindState的checkAdd进行检验,如果检验通过的话,加入到FindState的subscriberMethods内。看看checkAdd方法对什么进行检验?

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

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

    String methodKey = methodKeyBuilder.toString();
    Class methodClass = method.getDeclaringClass();
    Class methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
    if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
        // Only add if not already found in a sub class
        return true;
    } else {
        // Revert the put, old class is further down the class hierarchy
        subscriberClassByMethodKey.put(methodKey, methodClassOld);
        return false;
    }
}

checkAdd方法第一步先检验之前否有订阅过同一个EventType,如果有,在checkAddWithMethodSignature里再进一步检查key为methodName>eventTypeName的字符串是否存在。这里也是一个优化点,利用第一步检查,多数情况下避免了第二步利用了反射去获取methodName>eventTypeName对应的key。

通过这个校验我们知道两点:
① 允许一个类有多个方法名不同的方法对同个事件进行订阅。
② 如果子类重载了父类的订阅方法,以子类的为准。在checkAddWithMethodSignature检查method>eventTypeName时,如果methodClassOld为null或者methodClassOld为method为父类或本身时才返回true,说明子类重载这个订阅方法时,以子类的为准。

很多人认为在寻找SubscriberMethod时,是从子类到父类的,那isAssignableFrom似乎一直返回false,那意义是什么?其实这个作用主要发挥在反射时的,将在反射时介绍。

如果返回的SubscriberInfo为null的话,说明没有索引类。因此findUsingReflectionInSingleClass使用效率较低的反射方式。找到SubscriberMethod后,通过moveToSuperclass一层层向上寻找。最后getMethodsAndRelease重置FindState内的临时变量,并放置到对象池中。

2.2. 反射获取SubscriberMethod

如果ignoreGeneratedIndex为true时,采用反射的方式获取SubscriberMethod。而且如果使用了EventBus3.0,却不配置使用索引类,这样其实最后都会“降级”为反射。

值得注意的是,如果采用EventBus3.0却不使用注解处理器的方式效率是比EventBus2.4还要低的。因为EventBus2.4是固定订阅方法名为onEvent+ThreadMode的形式,而3.0方法名是自定义的,需要添加@Subscribe注解,相比之下多了反射获取注解的时间。

private List findUsingReflection(Class subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        findUsingReflectionInSingleClass(findState);
        findState.moveToSuperclass();
    }
    return getMethodsAndRelease(findState);
}

采用反射方式SubscriberMethod的流程也差不多,调用findUsingReflectionInSingleClass获取此类的SubscriberMethod后,一层层向上。最后释放FindState内的临时变量,并放置到对象池中。

看看如何通过findUsingReflectionInSingleClass获取一个类的SubscriberMethod:

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;
    }
    // 遍历Method,寻找包含@Subscribe注解的方法,并对合法性进行检测。
    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,先获取类里面的Method,通过getDeclaredMethods()或者getMethods()。这两个区别在于:getDeclaredMethods()返回这个类所有的方法,而getMethods()返回的是这个类及其父类的public的方法。因为在Activity这种继承关系很复杂的类里,getMethods()返回包含了很多系统的方法,大大降低了效率。

获取到Method数组后,校验包含@Subscribe注解的方法是不是为Public,是不是不含有abstract、static、bridge、synthtic修饰符,参数是不是只有一个。通过的话,再调用FindState的checkAdd校验,然后加到FindState的subscriberMethods里。

前面我们提到checkAdd内调用到的isAssignableFrom似乎没有意义,既然在寻找SubscriberMethod时,是一层层向上的,是不是isAssignableFrom一直返回false?其实不然,getMethods会得到这个类以及父类的public方法,因此isAssignableFrom是可能返回true的。

到这里注册订阅者的流程就结束了。

3. 发送事件

发送事件时,通过EventBus.getDefault.post(Event)来发送:

/** Posts the given event to the event bus. */
public void post(Object event) {
    PostingThreadState postingState = currentPostingThreadState.get();
    List 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;
        }
    }
} 
  

EventBus会通过ThreadLocal为每个线程维护一个PostingThreadState对象,里面包含分发队列eventQueue、是否主线程isMainThread、是否分发中isPosting、是否取消canceled、当前正在分发的事件和Subscription。

post方法这里的逻辑比较简单,将事件加到队列中,如果此时未在分发中时,就调用postSingleEvent逐一分发。

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    Class eventClass = event.getClass();
    boolean subscriptionFound = false;
    if (eventInheritance) {
        List> 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));
        }
    }
}

如果eventInheritance为true的话,表示事件支持继承,会调用lookupAllEventTypes获得需要分发的事件列表(包含自身、父类与接口)。然后使用postSingleEventForEventType分发事件。如果找不到相应的订阅者的话,根据sendNoSubscriberEvent与logNoSubscriberMessages决定是否发送NoSubscriberEvent事件与打印日志。

继续跟踪postSingleEventForEventType:

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class eventClass) {
    CopyOnWriteArrayList subscriptions;
    synchronized (this) {
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    if (subscriptions != null && !subscriptions.isEmpty()) {
        for (Subscription subscription : subscriptions) {
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted = false;
            try {
                postToSubscription(subscription, event, postingState.isMainThread);
                aborted = postingState.canceled;
            } finally {
                postingState.event = null;
                postingState.subscription = null;
                postingState.canceled = false;
            }
            if (aborted) {
                break;
            }
        }
        return true;
    }
    return false;
}

通过在注册订阅者时得到的subscriptionsByEventType获取到这个事件的订阅者及订阅方法,依次调用postToSubscription进行分发。

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
        case POSTING:
            invokeSubscriber(subscription, event);
            break;
        case MAIN:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case 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);
    }
}

这里涉及到EventBus的四种ThreadMode:

  • POSTING:在发布事件的线程执行。
  • MAIN:在主线程执行。
  • BACKGROUND:如果发布事件的线程为主线程则新建一个线程执行,否则在发布事件的线程执行。
  • ASYNC:在新的线程执行。

理解了这四种模式,就不难理解背后的原理。POSTING无需多说,invokeSubscriber方法内利用Subscription里面的SubscriberMethod,反射调用订阅事件的方法。其实我们也能猜到,切换到主线程是用的Handler,而切换到新线程则使用线程池。

在将这三种ThreadMode之前,我们需要了解PendingPost这个类。PendingPost作为PendingPostQueue(PendingPost的队列)的一个元素,代表了一个待发送的事件。

final class PendingPost {
    private final static List pendingPostPool = new ArrayList();

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

}

PendingPost里面持有事件event、订阅者信息subscription以及队列的下个节点next。仔细看下PendingPost里面的static变量(List)以及static方法(obtainPendingPost和releasePendingPost),其实跟前面分析的FindState一样都利用了对象池的思想避免的对象的频繁创建。

ThreadMode.MAIN:
当ThreadMode是Main时,如果当前是主线程,直接利用invokeSubscriber去处理;如果当前不是主线程的话,则调用HandlerPoster.enqueue去处理。

final class HandlerPoster extends Handler {

    private final PendingPostQueue queue;
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    // ......

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

enqueue方法内先利用PendingPost里的对象池获取PendingPost实例,enqueue到队列中。然后利用Handler将线程切换到主线程中。可以看到在handleMessage里面,最后也是交给invokeSubscriber去处理。

ThreadMode.BACKGROUND:
当ThreadMode是BACKGROUND时,如果当前不是主线程的话,直接交给invokeSubscriber去处理;否则,利用BackgroundPoster.enqueue切换到后台线程;

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

}

这里的处理过程是类似的,先通过PendingPost对象池获取实例,添加到PendingPostQueue中。利用EventBus类里的线程池executorService切换到后台线程。在run方法内,从队列中取出PendingPost后,同样交给invokeSubscriber处理。

ThreadMode.ASYNC:
当ThreadMode是ASYNC时,直接AsyncPoster.enqueue切换到新线程。

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

}

AsyncPoster跟BackGroundPoster的操作基本一致。

发送事件的流程图可以总结如下:
EventBus源码分析_第2张图片

注销订阅者

public synchronized void unregister(Object subscriber) {
    List> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        for (Class eventType : subscribedTypes) {
            unsubscribeByEventType(subscriber, eventType);
        }
        typesBySubscriber.remove(subscriber);
    } else {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}

注销订阅者比较简单,调用unsubscribeByEventType逐一取消订阅即可。

private void unsubscribeByEventType(Object subscriber, Class eventType) {
    List 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--;
            }
        }
    }
}

获取订阅某个事件的Subscription列表,将active标示为false。

粘性事件

所谓粘性事件,指的是订阅者在事件发送之后才注册的也能接收到的事件。发送粘性事件是通过EventBus.getDefault().postSticky():

public void postSticky(Object event) {
    synchronized (stickyEvents) {
        stickyEvents.put(event.getClass(), event);
    }
    // Should be posted after it is putted, in case the subscriber wants to remove immediately
    post(event);
}

除了像普通事件那样发送,还将事件记录到stickyEvents中。

既然粘性事件是在注册时能接收到之前发送的事件,看看注册时subscribe有关的逻辑:

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {

    // …… 

    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).
            Set, Object>> entries = stickyEvents.entrySet();
            for (Map.Entry, 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);
        }
    }
}

粘性事件,如果是继承的,对于事件自身和父类都调用checkPostStickyEventToSubscription,否则只对事件自身。

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) {
    // …… 
}

checkPostStickyEventToSubscription方法内调用了postToSubscription,postToSubscription我们在上面分析过了,不做冗余。

可以看到粘性事件其实很简单,只是将事件缓存起来,等到注册订阅者时再做判断。

索引类

在注册订阅者时,如果配置了索引类,就通过索引类直接来获取SubscriberInfo,免去了低效的反射过程。这个索引类就是在编译时通过注解处理器生成的。在分析注解处理器前,先看看它的“杰作”长什么样子:

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

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

        putIndex(new SimpleSubscriberInfo(MainActivity.class, true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onMessageEvent", MessageEvent.class, ThreadMode.MAIN),
        }));

    }

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

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

可以看到MyEventBusIndex存储了以订阅者Class为key,SubscriberInfo为value的Map。

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

        // ……
        collectSubscribers(annotations, env, messager);
        checkForSubscribersToSkip(messager, indexPackage);

        if (!methodsByClass.isEmpty()) {
            createInfoIndexFile(index);
        } else {
            messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found");
        }
        writerRoundDone = true;
    } catch (RuntimeException e) {
        // IntelliJ does not handle exceptions nicely, so log and print a message
        e.printStackTrace();
        messager.printMessage(Diagnostic.Kind.ERROR, "Unexpected error in EventBusAnnotationProcessor: " + e);
    }
    return true;
}

在process里首先获取配置在grade里面的eventBusIndex参数,即生成类的完整路径。如果获取不到,则结束。然后collectSubscribers获取所有订阅者的信息,checkForSubscribersToSkip筛选掉不符合的订阅者。最后利用createInfoIndexFile生成索引类。

collectSubscribers:

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

遍历需要处理的注解集合annotations,通过env.getElementsAnnotatedWith获取包含这个注解的元素。如果注解是修饰在ExecutableElement(方法)上的话,先通过checkHasNoErrors检验修饰符不为static、为public、只包含一个参数,然后加入到methodsByClass内。

checkForSubscribersToSkip:

/**
  * Subscriber classes should be skipped if their class or any involved event class are not visible to the index.
  */
private void checkForSubscribersToSkip(Messager messager, String myPackage) {
    for (TypeElement skipCandidate : methodsByClass.keySet()) {
        TypeElement subscriberClass = skipCandidate;
        while (subscriberClass != null) {
            if (!isVisible(myPackage, subscriberClass)) {
                boolean added = classesToSkip.add(skipCandidate);
                // …… 
                break;
            }
            List methods = methodsByClass.get(subscriberClass);
            if (methods != null) {
                for (ExecutableElement method : methods) {
                    String skipReason = null;
                    VariableElement param = method.getParameters().get(0);
                    TypeMirror typeMirror = getParamTypeMirror(param, messager);
                    if (!(typeMirror instanceof DeclaredType) ||
                            !(((DeclaredType) typeMirror).asElement() instanceof TypeElement)) {
                        skipReason = "event type cannot be processed";
                    }
                    if (skipReason == null) {
                        TypeElement eventTypeElement = (TypeElement) ((DeclaredType) typeMirror).asElement();
                        if (!isVisible(myPackage, eventTypeElement)) {
                            skipReason = "event type is not public";
                        }
                    }
                    if (skipReason != null) {
                        boolean added = classesToSkip.add(skipCandidate);
                        // …… 
                    }
                }
            }
            subscriberClass = getSuperclass(subscriberClass);
        }
    }
}

checkForSubscribersToSkip里校验了:
① 检查订阅者类与事件类是不是public或者与索引类在同一包路径下,即可访问的。
② 参数需要为对象与接口,不可以是int、double等基础类型,但是可以对应的包装类。

对于那些checkForSubscribersToSkip不通过的类,也能在运行时通过反射来工作,具体可以见上面的findUsingInfo方法的分析。

createInfoIndexFile:

createInfoIndexFile通过IO方法来生成索引类,比较容易理解,这里就不分析了。

结语

一路分析下来,我们发现EventBus其实逻辑不复杂。

通过在注册Subscriber时,先获取Subscriber内所有的SubscriberMethod,然后将订阅者Subscriber及其订阅的事件、订阅事件及其订阅者信息Subscription分别关联起来起来,使得在发送事件时能通过反射调用订阅方法。而获取SubscriberMethod的过程,要么是通过findUsingInfo在索引类里直接获取,要么是通过findUsingReflection反射获取带有@Subscribe的方法,前者的效率大大优于后者。而粘性事件的原理也很简单,在发送时将事件保存起来,而在注册时检查是不是有对应的粘性事件。

不仅如此,我们可以发现EventBus内为了追求效率做了很多优化,例如利用对象池避免对象的频繁创建、利用缓存变量避免多次调用反射等。

以上!

你可能感兴趣的:(EventBus源码分析)