EventBus 源码分析

来源:互联网 发布:希捷 数据恢复 编辑:程序博客网 时间:2024/05/21 23:37

前言

上篇文章笔者简单介绍了 EventBus 的用法。本篇文章笔者将简单分析 EventBus 的源码。从上篇文章我们可以得知,要使用 EventBus 首先要调用 EventBus 的 register 方法注册(一般在 onCreate 方法中)。然后,定义被 Subscribe 注解的方法(用来接收由 post 方法发送的消息)。最后,调用 unregister 方法解注册(一般在 onDestroy 方法中)。所以,笔者注重分析 EventBus 的 register , post 方法的实现,以及 EventBus 是如何调用接收消息的方法的。

register

EventBus.getDefault().register(this);

我们一般调用上述代码进行注册,调用上述代码的类我们暂且称为注册类。其中 getDefault 方法获取 EventBus 的实例。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);        }      }    }

先来看 3 , 4 行:这里调用 subscriberMethodFinder.findSubscriberMethods(subscriberClass) 得到一个 SubscriberMethod 的 List 。其中 SubscriberMethod 是对注册类中接收消息的方法的 Method 对象的封装。subscriberMethodFinder 是 SubscriberMethodFinder 类型的,我们接着追踪 SubscriberMethodFinder 的 findSubscriberMethods 方法。

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

第 2 行:List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); 其中 METHOD_CACHE 是 Map

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

由上述代码可以看出,findUsingReflectionInSingleClass 获取注册类中定义的方法并且遍历这些方法,然后把 public 、非 static 、非 abstract 、非 synthetic 、一个参数的、并且被注解 Subscribe 标注的方法封装成 SubscriberMethod 对象。并添加到 List subscriberMethods 中。然后把 subscriberMethods 返回给 findUsingInfo 方法,并最终返回给 EventBus 的 register 方法。接下来我们重新回到 register 方法。
register 方法中第 6 7 8 行 对返回的 List subscriberMethods 的遍历并调用 subscribe 方法。subscribe 方法的源码如下:

    // Must be called in synchronized block    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);      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);        }      }    }

在 subscribe 方法中,把
subscriberMethod 和注册类对象封装成 Subscription 对象 newSubscription 。 并将 newSubscription 添加到 CopyOnWriteArrayList subscriptions 中并且通过 subscriberMethod.priority 确定 newSubscription 在 subscriptions 中的位置。subscriberMethod.priority 其实就是方法执行的优先级。需要注意的是,subscriptions 会被保存到 subscriptionsByEventType 中,subscriptionsByEventType 是一个 Map ,其 key 是注册类中被注解的方法的参数的类型,也就是接受消息的方法的参数的类型。 至此 register 方法大概介绍完毕。下面来看 post 方法。

post

EventBus 的 post 方法 是 EventBus 用来发布消息的方法。 post 方法被调用后会将 post 方法的参数传递给相应的注册类中的相应的方法中,并调用此方法。这个过程是怎样的呢?请看 post 的源码:

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

由上述源码可以看出,第 4 , 5 行把 post 方法的参数添加到一个 List 中。第 8 行得到 post 方法是否是在 mian 线程中调用的。第 14 15 16 行对保存 post 方法参数的 List 遍历删除并调用 postSingleEvent 方法。在 postSingleEvent 方法中会调用 postSingleEventForEventType 方法。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 中相应的 Subscription 的 CopyOnWriteArrayList subscriptions。如果 subscriptions 不为空则遍历它,并调用 postToSubscription 。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);      }    }

由上述代码可以看出,postToSubscription 通过注解 Subscription 的属性 threadMode 的值,决定相应的接受信息的方法在哪个线程里调用。调用的规则已经在上篇文章中阐述过,这里不再赘述。invokeSubscriber 方法其实就是利用反射来实现接受信息的方法的调用的,这里也不再详细说明。

总结

EventBus 的实现其实就是一个典型的观察者模式。注册类向 EventBus 注册,当有消息需要发送的时候 EventBus 通过 post 方法向注册者们分发消息,其实就是遍历调用注册类中符合要求的方法。

0 0