EventBus3.0 源码解析以及跨进程事件机制

3,268 阅读17分钟

一、类定义

  • 为了更好的说明问题,在介绍EventBus源码以及机制之前,我们先定义两个类:EventClass,SubscriberClass分别泛指用户自定义的事件类和事件的订阅者, eventObject, subscriberObject分别泛指订阅者和被订阅事件的实例。

EventClass

public class EventClass {
    private String message;
    public EventClass() {
    }
    public EventClass(String message) {
        this.message = message;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}

SubscriberClass

public class SubscriberClass {
    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void onMessageEvent(EventClass eventObject) {
        Log.e("MessageSubscriber", "onMessageEvent1:" + eventObject.getMessage());
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND, priority = 2,sticky = true)
    public void onMessageEvent3(EventClass eventObject) {
        Log.e("MessageSubscriber", "onMessageEvent3:" + eventObject.getMessage());
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND, priority = 10,sticky = true)
    public void onMessageEvent4(EventClass eventObject) {
        Log.e("MessageSubscriber", "onMessageEvent4:" + eventObject.getMessage());
    }

    @Subscribe(threadMode = ThreadMode.ASYNC, priority = 100,sticky = true)
    public void onMessageEvent5(EventClass eventObject) {
        Log.e("MessageSubscriber", "onMessageEvent5:" + eventObject.getMessage());
    }
}

二、使用方式:

  • 订阅者注册,事件触发

1.注册订阅者:

SubscriberClass subscriberObject = new SubscriberClass();
EventBus.getDefault().register(subscriberObject);

2.触发事件:

EventBus.getDefault().post(new EventClass("Hello World"));

3.接收事件: 事件被post出后,就可以在subscriberObject对象的各个参数为EventClass方法中接收到了。可见subscriberObject在使用方法上非常像接口对象,等待被回调。

三、EventBus类:

  • 在我们了解EventBus的订阅,触发逻辑之前,我们先来了解一下EventBus

EventBus类中的关键属性:

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; 
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;
private final ThreadLocal<PostingThreadState> currentPostingThreadState;
private final SubscriberMethodFinder subscriberMethodFinder;
1.subscriptionsByEventType
  • key:eventObject的Class;value:一个线程安全的Subscription列表。 我们先来了解一下Subscription类: Subscription

      final Object subscriber;    // 注册EventBus事件接收者的对象。即我们上面定义的subscribeObject;显然一个Subscription的粒度是订阅者对象级别,而不是类级别。
      final SubscriberMethod subscriberMethod; // 一个事件捕捉者的封装类对象
    

    SubscriberMethod

      final Method method;           // 捕捉事件的方法即 subcribeObject的某个参数类型为eventType的method
      final ThreadMode threadMode;  // 从方法注解中解析出的方法的相关描述信息:线程模型
      final Class<?> eventType;    // 方法的参数类型,即上文定义的eventObject的参数类。
      final int priority;         // 事件优先级
      final boolean sticky;      // 是否是stickEvent
      String methodString;      // 相当于一个方法的标签,用于比较是否相同
    

    由以上代码以及注释可见:Subscription是一个事件的执行单元。因此 EventBus的属性**subscriptionsByEventType**的作用非常关键,当post eventObject时,会根据eventObject的类型通过 subscriptionsByEventType.get(eventObject.getClass())获取到一个Subscription,使用Subscription通过反射调用subscribeObject的相关方法,从而使订阅者接收到事件。当然具体的调用过程略复杂,我们稍后讲解。

2.typesBySubscriber
  • key:观察者subscribeObject; value:subscribeObject类的所有被观察者(eventObject)的Class。 typesBySubscriber主要在unregist的过程中起作用(regist时生成和更新),unregist时,根据订阅者(subscribeObject)的类型(key),找到所有被订阅事件(eventObject)的类型List,根据事件类型在subscriptionsByEventType中找到所有观察者Subscriptions,如果Subscription的执行者是subscribeObject,则移除(因为显然一个Subscription是订阅者对象级别,而非类级别)。所以typesBySubscriber只起到记录作用。
3.stickyEvents
  • key:被观察者(事件)类型;value:被观察者(事件对象)。可见,相同的事件类型只会存储最近一次发送的事件。
4.currentPostingThreadState
  • 场景: 存储当前线程的事件发送状况。当post一个事件,如果当前线程正在post事件则会进入post事件池,否则while循环从事件池不断取出事件,调用postSingleEvent(Object event, PostingThreadState postingState)方法,找到所有订阅者类名。分别调用postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass)调用‘subscriptionsByEventType.get()’获取所有当前事件的Subscription,
    • **PostingThreadState**类:

      final static class PostingThreadState {
         final List<Object> eventQueue = new ArrayList<>();
         boolean isPosting;              // 当前线程是否正在发送事件
         boolean isMainThread;          // 当前线程是否是MainThread
         Subscription subscription;    // 正在发送的事件的正在发送给的订阅者;
         Object event;                // 被观察者,事件
         boolean canceled;           // 事件是否被取消了,事件一般会被更高优先级的事件取消。
      }
      
5.subscriberMethodFinder
  • SubscriberMethodFinder类对象 对外只提供了findSubscriberMethods方法。此类的作用是通过subscribeObject对象的类型,找到此类中所有的事件接收方法。封装成List。在EventBus类的逻辑用于生成和更新subscriptionsByEventTypetypesBySubscriber。具体组装逻辑在后面章节讲解,此类也是EventBus2.x和EventBus3.x的主要区别。
6.标记性属性:以下EventBus中的标记性属性比较简单
private final boolean throwSubscriberException;    // 在反射调用subscriberObject中的方法失败时是否抛出异常
private final boolean logSubscriberExceptions;    // 在反射调用subscriberObject中的方法失败时是否打印log
private final boolean logNoSubscriberMessages;        // post的eventObject无订阅者时是否打印log
private final boolean sendSubscriberExceptionEvent;  // 在反射调用subscriberObject中的方法失败时是否post出SubscriberExceptionEvent事件,用户可以像订阅普通事件一样订阅SubscriberExceptionEvent
private final boolean sendNoSubscriberEvent;  // post的eventObject无订阅者时是否post NoSubscriberEvent...
private final boolean eventInheritance;      // post的evntObject是否触发父类对象订阅者,默认为true
private final int indexCount;               // 注解生成类数量,没有实际用处。
private final Logger logger;
7.当然还有各类事件执行器。
private final Poster mainThreadPoster;     // 实际是 AndroidHandlerMainThreadSupport实例,规定了Looper为MainThreadLooper的HandlerPoster
private final BackgroundPoster backgroundPoster;
private final AsyncPoster asyncPoster;
private final ExecutorService executorService;    

根据subscribeObject--> Subscription--> SubscriberMethod--> Method 的注解,ThreadMode,分别使用不同方式在不同线程触发事件。这也是EventBus在各线程中进行穿插传递的原因。 并且AsyncPoster,BackgroundPoster,SubscriberPoster这些事件执行器都是在EventBusBuilder中初始化的Executors.newCachedThreadPool();

四、 EventBus3.0 事件机制

OK 分析完EventBus类中的基本属性之后,更详细的分析EventBus的事件机制,包括订阅者注册和事件触发两部分。

1.register源码分析:

EventBus3.0 订阅者注册的过程,实际为EventBus中的两个重要属性subscriptionsByEventType typesBySubscriber的组织构造过程。 EventBus3.0 之后提供了AnnnationProcessor机制,替换掉了一部分需要使用反射的地方(事件注册部分),大大提高了性能。但是在事件触发阶段依然会用到反射。

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找到注册对象的类中所有接收事件的方法封装成List<SubscriberMethod>, subscribe方法分别注册。

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    Class<?> eventType = subscriberMethod.eventType;
    
    // 填充subscriptionsByEventType
    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);  //-- 可见同一个对象,在unregist之前只能注册一次。
        }
    }

    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;
        }
    }
     // subscriptionsByEventType填充结束,开始填充typesBySubscriber
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);
    // typesBySubscriber 填充结束,针对stickEvent特殊处理:
    if (subscriberMethod.sticky) {
        // 如果当前的subscriberMethod封装的是接收sitckEvent的方法
        if (eventInheritance) {
            // 如果发送父类事件,默认为true
            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);
        }
    }
}

由源码可见,subscribe的过程,就是在EventBus中填充subscriptionsByEventTypetypesBySubscriber的过程,这两个属性的作用我们已经在上文讲解。同时,会有针对stickEvent的特别处理,代码注释中已经说明。

至此,事件注册的流程已经讲解清楚,接下来重点讲解一下**SubscriberMethodFinder**类,如何通过一个对象找到当前对象所有订阅事件的方法并封装成List<SubscribeMethod>

SubscriberMethodFinder类重要属性:

private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
private List<SubscriberInfoIndex> subscriberInfoIndexes;
private final boolean strictMethodVerification;
private final boolean ignoreGeneratedIndex;
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE]; 
  • METHOD_CACHE: key:subScirbeObject的类型,value,此订阅者类型中的订阅者方法列表。
  • subscriberInfoIndexes: 通过AnnnationProcessor自动生成的SubscriberInfoIndex子类对象列表。我们在使用EventBus3.0时用EventBus.builder().addIndex(SubscriberInfoIndex index) 的方式添加。
  • strictMethodVerification: 可通过EventBusBuilder中设置,默认为false,使用严格的方法验证。当设置为true时,如果订阅者类中使用@Subscribe注解的方法,参数个数不等于1,或者方法类型非法(@Subscribe method: must be public, non-static, and non-abstract)时抛出EventBusException.
  • ignoreGeneratedIndex: 可通过EventBusBuilder中设置,是否忽略AnnnationProcessor自动生成的SubscriberInfoIndex子类,默认为false。不忽略。否则完全使用反射的方法。
  • FIND_STATE_POOL: FindState享元池

SubscriberMethodFinder类构造函数

SubscriberMethodFinder(List<SubscriberInfoIndex> subscriberInfoIndexes, boolean strictMethodVerification,
                       boolean ignoreGeneratedIndex) {
    this.subscriberInfoIndexes = subscriberInfoIndexes;
    this.strictMethodVerification = strictMethodVerification;
    this.ignoreGeneratedIndex = ignoreGeneratedIndex;
}

在EventBus的构造函数中创建,前面已经讲解,subscriberMethodFinder是EventBus类的重要属性。

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) {
        return subscriberMethods;
    }

    if (ignoreGeneratedIndex) {
        // 忽略通过AnnnationProcessor自动生成的`SubscriberInfoIndex`子类,完全使用反射实现。
        subscriberMethods = findUsingReflection(subscriberClass);
    } else {
        // 使用SubscriberInfoIndex
        subscriberMethods = findUsingInfo(subscriberClass);
    }
    if (subscriberMethods.isEmpty()) {
        throw new EventBusException("Subscriber " + subscriberClass
                + " and its super classes have no public methods with the @Subscribe annotation");
    } else {
        //- 将subscriberMethods写入缓存。
        METHOD_CACHE.put(subscriberClass, subscriberMethods);
        return subscriberMethods;
    }
}

findSubscriberMethods方法是SubscriberMethodFinder类唯一对外暴露的方法,参数为订阅者方法类型,返回值为此订阅类中的所有事件接受者方法(即使用了@Subscriber注解的方法),并将方法封装为SubscriberMethodSubscriberMethod类前面已经讲解。

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

FindState类是SubscriberMethodFinder类的内部静态类。EventBus3.0 在用FindState类时,使用了享元模式,构造了一个FIND_STATE_POOL,默认存储4个。如果四个被同时占用则新创建一个。prepareFindState()的过程便是从池中获取或者new FindState。进入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;
    // 通过EventBusBuilder传过来的Index,调用getSubscriberInfo()来初始化;
    SubscriberInfo subscriberInfo;

    // 通过订阅者类初始化
    void initForSubscriber(Class<?> subscriberClass) {
        this.subscriberClass = clazz = subscriberClass;
        skipSuperClasses = false;
        subscriberInfo = null;
    }

    // 清除数据,备 FIND_STATE_POOL回收。
    void recycle() {
        subscriberMethods.clear();
        anyMethodByEventType.clear();
        subscriberClassByMethodKey.clear();
        methodKeyBuilder.setLength(0);
        subscriberClass = null;
        clazz = null;
        skipSuperClasses = false;
        subscriberInfo = null;
    }

    boolean checkAdd(Method method, Class<?> eventType) {
        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;
        }
    }
    void moveToSuperclass() {
        if (skipSuperClasses) {
            clazz = null;
        } else {
            clazz = clazz.getSuperclass();
            String clazzName = clazz.getName();
            /** Skip system classes, this just degrades performance. */
            if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
                clazz = null;
            }
        }
    }
}

几个类的继承关系: interface SubscriberInfo --> abstract class AbstractSubscriberInfo --> class SimpleSubscriberInfo

public interface SubscriberInfo {
    Class<?> getSubscriberClass();
    SubscriberMethod[] getSubscriberMethods();
    SubscriberInfo getSuperSubscriberInfo();
    boolean shouldCheckSuperclass();
}

interface SubscriberInfoIndex --> 自动生成的类 class MyEventBusIndex

public interface SubscriberInfoIndex {
    SubscriberInfo getSubscriberInfo(Class<?> subscriberClass);
}

AnnnationProcessor的作用便是在编译阶段,通过解析代码注解,生成MyEventBusIndex类,生成静态Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX,提供getSubscriberInfo方法的实现,可以根据订阅者类型返回SimpleSubscriberInfo。看一下SimpleSubscriberInfo源码:

public class SimpleSubscriberInfo extends AbstractSubscriberInfo {
    private final SubscriberMethodInfo[] methodInfos;
    public SimpleSubscriberInfo(Class subscriberClass, boolean shouldCheckSuperclass, SubscriberMethodInfo[] methodInfos) {
        super(subscriberClass, null, shouldCheckSuperclass);
        this.methodInfos = methodInfos;
    }
    @Override
    public synchronized SubscriberMethod[] getSubscriberMethods() {
        int length = methodInfos.length;
        SubscriberMethod[] methods = new SubscriberMethod[length];
        for (int i = 0; i < length; i++) {
            SubscriberMethodInfo info = methodInfos[i];
            methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode,
                    info.priority, info.sticky);
        }
        return methods;
    }
}

可以看到SimpleSubscriberInfo的构造函数中有一个参数methodInfos,类型为SubscriberMethodInfo,为什么不是SubscriberMethod呢?看一下SubscriberMethodInfo的源码:

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

可见SubscriberMethod在编译期的过渡类:SubscriberMethodInfo,之所以称它为过渡类,因为显然在编译阶段SubscriberMethod类的method字段在编译期不可能被生成。只有在运行时通过反射获取。在getSubscriberMethods方法中完成了这部分转化。方法中调用了createSubscriberMethod,方法在父类AbstractSubscriberInfo中实现:

protected SubscriberMethod createSubscriberMethod(String methodName, Class<?> eventType, ThreadMode threadMode,
                                                  int priority, boolean sticky) {
    try {
    // 在运行时通过反射得到Method,封装成SubscriberMethod
        Method method = subscriberClass.getDeclaredMethod(methodName, eventType);
        return new SubscriberMethod(method, eventType, threadMode, priority, sticky);
    } catch (NoSuchMethodException e) {
        throw new EventBusException("Could not find subscriber method in " + subscriberClass +
                ". Maybe a missing ProGuard rule?", e);
    }
}

正如我们分析的,method字段是在运行时(精确来讲是事件注册时)通过反射得到。

ok,以上是EventBus3.0,当使用AnnationProcessor时的注册流程,在不使用AnnationProcessor或者根据自动生成类找不到相关订阅方法类时,使用反射的方法完成注册。

private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        // This is faster than getMethods, especially when subscribers are fat classes like Activities
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
        methods = findState.clazz.getMethods();
        findState.skipSuperClasses = true;
    }
    for (Method method : methods) {
        int modifiers = method.getModifiers();
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length == 1) {
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                if (subscribeAnnotation != null) {
                    Class<?> eventType = parameterTypes[0];
                    if (findState.checkAdd(method, eventType)) {
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                        findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                    }
                }
            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException("@Subscribe method " + methodName +
                        "must have exactly 1 parameter but has " + parameterTypes.length);
            }
        } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
            String methodName = method.getDeclaringClass().getName() + "." + method.getName();
            throw new EventBusException(methodName +
                    " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
        }
    }
}

这些代码比较简单,根据FindState中存储的类名,遍历该类下的方法,过滤EventBus3.0不支持的方法类型。根据注解将方法封装成一个个SubscriberMethod。最终效果与使用AnnationProcessor相同得到List<SubscriberMethod>

至此,SubscriberMethodFinder类已经分析完成。简单来讲,SubscriberMethodFinder类的作用便是根据订阅者的类型找到一系列订阅者方法并封装为List<SubscriberMethod>

2. unregister源码分析:

public synchronized void unregister(Object subscriber) {
    // 通过typesBySubscriber找到订阅者订阅的所有事件类型类
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        for (Class<?> eventType : subscribedTypes) {
            // 根据订阅者和事件类型,清除subscribeByEventType中相关存储
            unsubscribeByEventType(subscriber, eventType);
        }
        // 将事件订阅者从typesBySubscriber中移除
        typesBySubscriber.remove(subscriber);
    } else {
        logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
    //  找到当前事件类型的所有 Subscription,如果Subscription对应的object是当前subscriber则将活跃性设置为false,并从subscriptionsByEventType中移除
    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--;
            }
        }
    }
}

由源码可见,EventBus的unregister过程,便是EventBus类中typesBySubscribersubscriptionsByEventType 清除订阅者的过程。

3. 事件触发源码分析:

public void post(Object event) {
    PostingThreadState postingState = currentPostingThreadState.get();
    List<Object> eventQueue = postingState.eventQueue;
    eventQueue.add(event);
    if (!postingState.isPosting) {
        postingState.isMainThread = isMainThread();
        postingState.isPosting = true;
        if (postingState.canceled) {
            throw new EventBusException("Internal error. Abort state was not reset");
        }
        try {
            while (!eventQueue.isEmpty()) {
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}

currentPostingThreadState我们上文已经分析。post(Object event)时,首先获取当前线程的事件发送状态postingState,将event存入eventQuene。如果isPosting==false,则循环从eventQuene中取出消息,执行postSingleEvent方法。(由于postingState存储于ThreadLocal中,每个线程获取的postingState都是不同的,然而同一个线程中的代码是顺序执行的,所以怎么会遇到postingState.isPosting==true的情况呢,不知道为什么EventBus会使用eventQuene,并加这样的判断。对此可以给出合理解释的同学欢迎联系我,虚心求教,EventBus官方给出的解释是他们对ThreadLocal机制不太了解)。

进入postSingleEvent方法。

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;
    if (eventInheritance) {
        // 如果支持发送父类事件,则获取所有的父类
        List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
        int countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
            Class<?> clazz = eventTypes.get(h);
            subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
        }
    } else {
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    }
    if (!subscriptionFound) {
        if (logNoSubscriberMessages) {
            logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
        }
        if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) {
            post(new NoSubscriberEvent(this, event));
        }
    }
}

可见,postSingleEvent方法中通过eventInheritance(上文已经分析)做判断是否触发订阅了事件父类事件类型的订阅者接收,eventInheritance默认为true,找到所有父类已经接口类,进入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;
}

postSingleEventForEventType方法中通过subscriptionsByEventType属性获取所有订阅了当前事件类型的订阅者封装对象subscriptions,for循环递归处理事件分发,首先填充postingState部分字段,可见postingState在post的过程中起上下文的作用。之后调用方法postToSubscription()

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    if (event instanceof MultiProcessSerializeEvent && ((MultiProcessSerializeEvent) event).isSendToCenter()) {
        if (subscription.subscriberMethod.threadMode == ThreadMode.MULTI_PROCESS)
            processPoster.enqueue(subscription, event);
        return;
    }
    switch (subscription.subscriberMethod.threadMode) {
        case POSTING:
            invokeSubscriber(subscription, event);
            break;
        case MAIN:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case MAIN_ORDERED:
            if (mainThreadPoster != null) {
                mainThreadPoster.enqueue(subscription, event);
            } else {
                invokeSubscriber(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);
    }
}

由源码可见,postToSubscription方法中根据subscription中的Method的threadMode的不同,即接收者线程的不同,使用不同的Poster进行处理。

ThreadMode.POSTING:在事件触发线程执行事件:

subscription.subscriberMethod.method.invoke(subscription.subscriber, event); 

非常简单,直接使用反射,执行订阅者对象的订阅方法。

  • ThreadMode.MAIN: 判断当前线程如果为主线程则直接反射调用,否则mainThreadPoster处理,mainThreadPoster实际上是一个HandlerPoster,分析一下HandlerPoster的源码:
public class HandlerPoster extends Handler implements Poster {
    private final PendingPostQueue queue;
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        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;
        }
    }
}

EventBus类中的invokeSubscriber

void invokeSubscriber(PendingPost pendingPost) {
    Object event = pendingPost.event;
    Subscription subscription = pendingPost.subscription;
    // 显然PendingPost也使用了享元模式
    PendingPost.releasePendingPost(pendingPost);
    // 是否已经unregister判断
    if (subscription.active) {
        invokeSubscriber(subscription, event);
    }
}
    

显然代码很简单,只不过一个包含了消息队列PendingPostQueue的Handler, enqueue时将消息存入消息队列,同时触犯sendMessage,在handleMessage()中循环遍历消息队列,将事件取出, 发给EventBus通过反射调用。由于Handler的handleMessage()执行于Looper的创建线程,而HandlerPoster创建时使用的Looper正式Looper.mainLooper()得到,所以保证了hreadMode.MAIN在主线程触发。

  • ThreadMode.MAIN_ORDERED: 大体与ThreadMode.MAIN相同,不过优先进入mainThreadPoster队列。这很大程度上保证了订阅者接收事件的顺序与发送事件的顺序相同。
  • ThreadMode.BACKGROUND:
final class BackgroundPoster implements Runnable, Poster {
    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) {
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

}

如果当前线程为非MAIN线程则直接调通过反射调用,否则使用BackgroundPoster的实例发送事件,其实与HandlerPoster并没有太大差异,不过是一个Runnable,执行在Executors.newCachedThreadPool()线程池。保证一定会在异步线程执行。但是值得注意的是,既然已经使用了线程池,为什么还要使用PendingPostQueue呢?显然通过源码我们可以知道,在enqueue时如果有正在处理的事件则将事件写入PendingPostQueue,run()时再从quene中取出,这样做的作用是尽量保证事件执行的顺序。同样这也造成了,如果使用ThreadMode.BACKGROUND执行很耗时的后台操作,可能会造成后台任务阻塞(等待前面的任务执行完成)。

  • ThreadMode.ASYNC:

ThreadMode.ASYNC 使用的AysncPosterBackgroundPoster大体相同,并且同样使用了Executors.newCachedThreadPool()线程池,但是抛弃了PendingPostQueue,而且所有执行的信任都会在线程池中直接执行。所以ThreadMode.ASYNC模式适合耗时的异步任务。不会造成后台线程阻塞。

至此EventBus3.0源码已经完全分析完成。

五、修改EventBus3.0 支持多进程通讯

  • EventBus3.0 并没有提供任何跨进程的处理方案。我们修改一下,添加一种事件模式ThreadMode.MULTI_PROCESS。
1. 使用AIDL的方式实现多进程间双向通讯。以应用的主进程作为消息的处理中心。
2. 处理多进程情况下的StickEvent,所有进程的发送的stickEvent都要在消息中心备份,这样当新的进程刚刚创建时便可以发送stickEvent,从而可以实现多进程之间状态的同步。
3. 改写register,简历subscriberQuene, 使得当前进程与消息处理中心建立连接之后才可以真正注册,防止漏发stickEvent
4. 改写代码将开源。