• Android事件总线(四)源码解析otto


    前言

    上一篇文章中讲到了otto的用法,这一篇我们来讲一下otto的源码。可能有人觉得otto过时了,但是通过源码我们学习的是高手设计otto时的设计理念,这种设计理念是不过时的。

    otto各个类的作用

    首先先来看一下otto的源码的各个类的作用,如下图所示。

    如图所示,otto的源码并不多,主要的类的功能如下:

    • Produce、Subscribe:发布者和订阅者注解类。
    • Bus:事件总线类,用来注册和取消注册,维护发布-订阅模型,并处理事件调度分发。
    • HandlerFinder、AnnotatedHandlerFinder:用来查找发布者和订阅者。
    • EventProducer、EventHandler:分别封装发布者和订阅者的数据结构。

    otto构造函数

    在使用otto时,首先要创建Bus类,Bus类的构造函数如下所示。

    public Bus() {
        this(DEFAULT_IDENTIFIER);
    }
    View Code

    这个DEFAULT_IDENTIFIER是一个字符串”default”,this调用了Bus类的另一个构造函数:

    public Bus(String identifier) {
       this(ThreadEnforcer.MAIN, identifier);
     }
    View Code

    ThreadEnforcer.MAIN意味着默认在主线程中调度事件,再往里看this又调用了什么,如下所示。

    public Bus(ThreadEnforcer enforcer, String identifier) {
      this(enforcer, identifier, HandlerFinder.ANNOTATED);
    }
    View Code

    第一个参数我们提到了,就是事件调度的简称,identifier为Bus的名称,默认为”default”。而identifier则是HandlerFinder,用于在register、unregister的时候寻找所有的subscriber和producer。再往里查看this又调用了什么,如下所示。

    Bus(ThreadEnforcer enforcer, String identifier, HandlerFinder handlerFinder) {
      this.enforcer =  enforcer;
      this.identifier = identifier;
      this.handlerFinder = handlerFinder;
    }
    View Code

    这个是最终调用的Bus的构造函数,在这里要首先记住handlerFinder 指的就是传进来的HandlerFinder.ANNOTATED,后面在注册时会用到handlerFinder这个属性。

    注册

    生成bus类后,我们要调用它的register方法来进行注册。register方法如下所示。

    public void register(Object object) {
        if (object == null) {
          throw new NullPointerException("Object to register must not be null.");
        }
        enforcer.enforce(this);
        Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);//1
    ...
    }
    View Code

    注释1出调用了handlerFinder的findAllProducers方法,此前讲到构造函数时,我们知道这个handlerFinder指的是HandlerFinder.ANNOTATED,ANNOTATED的代码如下所示。

    HandlerFinder ANNOTATED = new HandlerFinder() {
       @Override
       public Map<Class<?>, EventProducer> findAllProducers(Object listener) {
         return AnnotatedHandlerFinder.findAllProducers(listener);
       }
       @Override
       public Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) {
         return AnnotatedHandlerFinder.findAllSubscribers(listener);
       }
     };
    View Code

    从上面的代码的findAllProducers方法和findAllSubscribers方法的返回值可以推断出一个注册类只能有一个发布者,却可以有多个订阅者。findAllProducers方法最终调用的是AnnotatedHandlerFinder的findAllProducers方法:

    static Map<Class<?>, EventProducer> findAllProducers(Object listener) {
      final Class<?> listenerClass = listener.getClass();
      Map<Class<?>, EventProducer> handlersInMethod = new HashMap<Class<?>, EventProducer>();
      Map<Class<?>, Method> methods = PRODUCERS_CACHE.get(listenerClass);//1
      if (null == methods) {
        methods = new HashMap<Class<?>, Method>();
        loadAnnotatedProducerMethods(listenerClass, methods);//2
      }
      if (!methods.isEmpty()) {
        for (Map.Entry<Class<?>, Method> e : methods.entrySet()) {//3
          EventProducer producer = new EventProducer(listener, e.getValue());
          handlersInMethod.put(e.getKey(), producer);
        }
      }
      return handlersInMethod;
    }
    View Code

    PRODUCERS_CACHE是一个ConcurrentHashMap,它的key为bus.register()时传入的class,而value是一个map,这个map的key是事件的class,value是生产事件的方法。注释1处首先在PRODUCERS_CACHE根据传入的对象的类型查找是否有缓存的事件方法,如果没有就调用注释2处的代码利用反射去寻找所有使用了@Produce注解的方法,并且将结果缓存到PRODUCERS_CACHE中。接着在注释3处遍历这些事件方法,并为每个事件方法创建了EventProducer类,并将这些EventProducer类作为value存入handlersInMethod并返回。接下来我们返回register方法。如下所示。

    public void register(Object object) {
      if (object == null) {
        throw new NullPointerException("Object to register must not be null.");
      }
      enforcer.enforce(this);
      Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);
      for (Class<?> type : foundProducers.keySet()) {
        final EventProducer producer = foundProducers.get(type);
        EventProducer previousProducer = producersByType.putIfAbsent(type, producer);//1
        if (previousProducer != null) {
          throw new IllegalArgumentException("Producer method for type " + type
            + " found on type " + producer.target.getClass()
            + ", but already registered by type " + previousProducer.target.getClass() + ".");
        }
        Set<EventHandler> handlers = handlersByType.get(type);
        if (handlers != null && !handlers.isEmpty()) {
          for (EventHandler handler : handlers) {
            dispatchProducerResultToHandler(handler, producer);//2
          }
        }
      }
      ...
    }
    View Code

    调用完findAllProducers方法后,会在注释1处检查是否有该类型的发布者已经存在,如果存在则抛出异常,不存在则调用注释2处的dispatchProducerResultToHandler方法来触发和发布者对应的订阅者来处理事件。接下来register方法的后一部分代码就不帖上来了,跟此前的流程大致一样就是调用findAllSubscribers方法来查找所有使用了@Subscribe注解的方法,跟此前不同的是一个注册类可以有多个订阅者,接下来判断是否有该类型的订阅者存在,也就是判断注册类是否已经注册,如果存在则抛出异常,不存在则查找是否有和这些订阅者对应的发布者,如果有的话,就会触发对应的订阅者处理事件。

    发送事件

    我们会调用Bus的post方法来发送事件,它的代码如下所示。

    public void post(Object event) {
      if (event == null) {
        throw new NullPointerException("Event to post must not be null.");
      }
      enforcer.enforce(this);
      Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());//1
      boolean dispatched = false;
      for (Class<?> eventType : dispatchTypes) {
        Set<EventHandler> wrappers = getHandlersForEventType(eventType);
        if (wrappers != null && !wrappers.isEmpty()) {
          dispatched = true;
          for (EventHandler wrapper : wrappers) {
            enqueueEvent(event, wrapper);//2
          }
        }
      }
      if (!dispatched && !(event instanceof DeadEvent)) {
        post(new DeadEvent(this, event));
      }
      dispatchQueuedEvents();//3
    }
    View Code

    注释1处的flattenHierarchy方法首先会从缓存中查找传进来的event(消息事件类)的所有父类,如果没有则找到event的所有父类并存储入缓存中。接下来遍历这些父类找到它们的所有订阅者,并在注释2处将这些订阅者压入线程的事件队列中。并在注释3处调用dispatchQueuedEvents方法依次取出事件队列中的订阅者来处理相应event的事件。

    取消注册

    取消注册时,我们会调用Bus的unregister方法,unregister方法如下所示。

    public void unregister(Object object) {
      if (object == null) {
        throw new NullPointerException("Object to unregister must not be null.");
      }
      enforcer.enforce(this);
      Map<Class<?>, EventProducer> producersInListener = handlerFinder.findAllProducers(object);//1
      for (Map.Entry<Class<?>, EventProducer> entry : producersInListener.entrySet()) {
        final Class<?> key = entry.getKey();
        EventProducer producer = getProducerForEventType(key);
        EventProducer value = entry.getValue();
        if (value == null || !value.equals(producer)) {
          throw new IllegalArgumentException(
              "Missing event producer for an annotated method. Is " + object.getClass()
                  + " registered?");
        }
        producersByType.remove(key).invalidate();//2
      }
    ...
    }
    View Code

    取消注册分为两部分,一部分是订阅者取消注册,另一部分是发布者取消注册。这两部分的代码类似,因此,上面的代码只列出了发布者取消注册的代码。在注释1处得到所有使用@Produce注解的方法,并遍历这些方法,调用注释2处的代码从缓存中清除所有和传进来的注册类相关的发布者,来完成发布者的取消注册操作。

  • 相关阅读:
    win32
    win32
    win32
    win32
    C++ 指针的错误释放
    交换两个数不引入第三个变量
    交换两个数不引入第三个变量
    hdu3986 spfa + 枚举最短路上的边
    hdu3986 spfa + 枚举最短路上的边
    hdu2433 spfa+mark[x][u][v]优化
  • 原文地址:https://www.cnblogs.com/ganchuanpu/p/6058040.html
Copyright © 2020-2023  润新知