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

一、类定义

  • 为了更好的说明问题,在介绍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, CopyOnWriteArrayList> subscriptionsByEventType; 
private final Map>> typesBySubscriber;
private final Map, Object> stickyEvents;
private final ThreadLocal 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 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 subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
          synchronized (this) {
              for (SubscriberMethod subscriberMethod : subscriberMethods) {
                  subscribe(subscriber, subscriberMethod);
              }
          }
      }
      复制代码

      可见,注册的过程中通过subscriberMethodFinder找到注册对象的类中所有接收事件的方法封装成List, subscribe方法分别注册。

      private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
          Class eventType = subscriberMethod.eventType;
          
          // 填充subscriptionsByEventType
          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);  //-- 可见同一个对象,在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> 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, 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);
              }
          }
      }
      复制代码

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

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

      SubscriberMethodFinder类重要属性:

      private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>();
      private List 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 subscriberInfoIndexes, boolean strictMethodVerification,
                             boolean ignoreGeneratedIndex) {
          this.subscriberInfoIndexes = subscriberInfoIndexes;
          this.strictMethodVerification = strictMethodVerification;
          this.ignoreGeneratedIndex = ignoreGeneratedIndex;
      }
      复制代码

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

      List findSubscriberMethods(Class subscriberClass) {
          List 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 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 subscriberMethods = new ArrayList<>();
          final Map anyMethodByEventType = new HashMap<>();
          final Map 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, 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

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

      2. unregister源码分析:

      public synchronized void unregister(Object subscriber) {
          // 通过typesBySubscriber找到订阅者订阅的所有事件类型类
          List> 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 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 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> 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 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. 改写代码将开源。

      转载于:https://juejin.im/post/5a9e7ac6518825557b4c3ed5

      你可能感兴趣的:(EventBus3.0 源码解析以及跨进程事件机制)