EventBus源码分析

来源:互联网 发布:贝尔.格里尔斯 知乎 编辑:程序博客网 时间:2024/06/07 04:57

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

EventBus工作机制

这篇文章不对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<SubscriberMethod> 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<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);    // 粘性事件处理, 将在第五小节分析}

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

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

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

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

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

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

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

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

继续跟踪postSingleEventForEventType:

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

通过在注册订阅者时得到的subscriptionsByEventType获取到这个事件的订阅者及订阅方法,依次调用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<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);            }        }    }}

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发送事件流程图

注销订阅者

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

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

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

获取订阅某个事件的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<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);        }    }}

粘性事件,如果是继承的,对于事件自身和父类都调用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<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;    static {        SUBSCRIBER_INDEX = new HashMap<Class<?>, 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。

@Overridepublic boolean process(Set<? extends TypeElement> 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<? extends TypeElement> annotations, RoundEnvironment env, Messager messager) {    for (TypeElement annotation : annotations) {        Set<? extends Element> elements = env.getElementsAnnotatedWith(annotation);        for (Element element : elements) {            if (element instanceof ExecutableElement) {                ExecutableElement method = (ExecutableElement) element;                if (checkHasNoErrors(method, messager)) {                    TypeElement classElement = (TypeElement) method.getEnclosingElement();                    methodsByClass.putElement(classElement, method);                }            } else {                messager.printMessage(Diagnostic.Kind.ERROR, "@Subscribe is only valid for methods", element);            }        }    }}

遍历需要处理的注解集合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<ExecutableElement> methods = methodsByClass.get(subscriberClass);            if (methods != null) {                for (ExecutableElement method : methods) {                    String skipReason = null;                    VariableElement param = method.getParameters().get(0);                    TypeMirror typeMirror = getParamTypeMirror(param, messager);                    if (!(typeMirror instanceof DeclaredType) ||                            !(((DeclaredType) typeMirror).asElement() instanceof TypeElement)) {                        skipReason = "event type cannot be processed";                    }                    if (skipReason == null) {                        TypeElement eventTypeElement = (TypeElement) ((DeclaredType) typeMirror).asElement();                        if (!isVisible(myPackage, eventTypeElement)) {                            skipReason = "event type is not public";                        }                    }                    if (skipReason != null) {                        boolean added = classesToSkip.add(skipCandidate);                        // ……                     }                }            }            subscriberClass = getSuperclass(subscriberClass);        }    }}

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

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

createInfoIndexFile:

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

结语

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

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

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

以上!

原创粉丝点击