Event Bus 之 Otto(三)


register 过程:

register 接受一个Object实例做为参数,而后把该实例的producer和subscriber方法扫描出来。java

从代码注释可知, 若是你在订阅一个事件类型时, 这个类型已经注册了producer, 那么EventBus会当即调用producer产生事件向 刚注册的 subscribers发布。app

另外,一个事件类型只能对应一个producer, 不然抛出异常。less

还有就是要理解 ConcurrentMap 的 putIfAbsent 方法:若是指定的key-value 不存在则至关于put 操做, 不然至关于get 操做。ide

/**
   * Registers all handler methods on {@code object} to receive events and producer methods to provide events.
   * <p>
   * If any subscribers are registering for types which already have a producer they will be called immediately
   * with the result of calling that producer.
   * <p>
   * If any producers are registering for types which already have subscribers, each subscriber will be called with
   * the value from the result of calling the producer.
   *
   * @param object object whose handler methods should be registered.
   * @throws NullPointerException if the object is null.
   */
   
  public void register(Object object) {
    ...
    enforcer.enforce(this);

    //提取 producer
    Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);
    for (Class<?> type : foundProducers.keySet()) {

      final EventProducer producer = foundProducers.get(type);
      EventProducer previousProducer = producersByType.putIfAbsent(type, producer);
      
      //checking if the previous producer existed
      //一个事件类型只能有一个生产者
      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);
        }
      }
    }

    // 提取 subscriber
    Map<Class<?>, Set<EventHandler>> foundHandlersMap = handlerFinder.findAllSubscribers(object);
    for (Class<?> type : foundHandlersMap.keySet()) {
      Set<EventHandler> handlers = handlersByType.get(type);
      if (handlers == null) {
        //concurrent put if absent
        Set<EventHandler> handlersCreation = new CopyOnWriteArraySet<EventHandler>();
        handlers = handlersByType.putIfAbsent(type, handlersCreation);
        if (handlers == null) {
            handlers = handlersCreation;
        }
      }
      final Set<EventHandler> foundHandlers = foundHandlersMap.get(type);
      handlers.addAll(foundHandlers);
    }

    //对于新注册的订阅者,若是有producer,则当即向订阅者发布最新事件
    for (Map.Entry<Class<?>, Set<EventHandler>> entry : foundHandlersMap.entrySet()) {
      Class<?> type = entry.getKey();
      EventProducer producer = producersByType.get(type);
      
          if (producer != null && producer.isValid()) {
                Set<EventHandler> foundHandlers = entry.getValue();
                for (EventHandler foundHandler : foundHandlers) {
                      if (!producer.isValid()) {
                        break;
                      }
                      if (foundHandler.isValid()) {
                        dispatchProducerResultToHandler(foundHandler, producer);
                      }
                }
            
          }      
    }
    
  }


post 过程:

将一个事件向全部的subscribers发布,若是某个handler发生异常将被无视 :D oop

若是一个事件没有相应的subscriber来处理,那么这个事件将被包装成 DeadEvent 并从新发布;post

/**
   * Posts an event to all registered handlers.  This method will return successfully after the event has been posted to
   * all handlers, and regardless of any exceptions thrown by handlers.
   *
   * <p>If no handlers have been subscribed for {@code event}'s class, and {@code event} is not already a
   * {@link DeadEvent}, it will be wrapped in a DeadEvent and reposted.
   *
   * @param event event to post.
   * @throws NullPointerException if the event is null.
   */
  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());

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

    if (!dispatched && !(event instanceof DeadEvent)) {
      post(new DeadEvent(this, event));
    }

    dispatchQueuedEvents();
  }


跨线程问题

在register 和 post 方法中 都有一个enforcer 变量,它是ThreadEnforcer的实现, 用来限制register、post等方法调用的线程(通常只能在主线程中调用) ,你也能够实现本身的ThreadEnforcer来改变折中策略。this

另外eventToDispatch 以及 isDispatching 变量都使用了ThreadLocal , 这些也为你实现本身的ThreadEnforcer策略提供了支持,同时还能够看出,Otto是不能跨线程发布事件的, 若是确实须要这样作,要借助线程的Looper 或 AsyncTask 来实现。spa

  /** Thread enforcer for register, unregister, and posting events. */
  private final ThreadEnforcer enforcer;

  /** Queues of events for the current thread to dispatch. */
  private final ThreadLocal<ConcurrentLinkedQueue<EventWithHandler>> eventsToDispatch = new ThreadLocal<ConcurrentLinkedQueue<EventWithHandler>>() {
       
	  @Override protected ConcurrentLinkedQueue<EventWithHandler> initialValue() {
          return new ConcurrentLinkedQueue<EventWithHandler>();
        }
	  
      };

  /** True if the current thread is currently dispatching an event. */
  private final ThreadLocal<Boolean> isDispatching = new ThreadLocal<Boolean>() {
    @Override protected Boolean initialValue() {
      return false;
    }
  };
相关文章
相关标签/搜索