天天看點

事件總線Otto源碼解析

Otto 事件總線示例

Otto是釋出訂閱式架構。由Square開發,但是Square停止更新了,推薦用Rxjava來代替。還是來學習一下Otto的思想。

首先來看看示例,定義一個Otto管理類,封裝Bus的注冊、取消注冊,向外提供這些方法:

public class OttoBusManager {
    private static OttoBusManager instance;
    private Bus bus;

    public static OttoBusManager getInstance() {
        if (instance == null) {
            synchronized (OttoBusManager.class) {
                if (instance == null) {
                    instance = new OttoBusManager();
                }
            }
        }

        return instance;
    }

    private OttoBusManager() {
        bus = new Bus(ThreadEnforcer.ANY);
    }

    public void register(Object o) {
        bus.register(o);
    }

    public void unRegister(Object o) {
        bus.unregister(o);
    }
    public void notifyNotification(User user){
		bus.post(user);
	}
}
           

然後再看看事件發送者如何使用:

//建立時注冊:
OttoBusManager.getInstance().register(this);

//銷毀時登出:
OttoBusManager.getInstance().unRegister(this);
	 
//合适的地方發送通知:
OttoBusManager.getInstance().notifyNotification(new User());

//或者,給方法名添加注解
	@Produce
  Public BusData setInitialContent() {
        return new BusData("更新資料了");
 }
OttoBusManager.getInstance().notifyNotification(setInitialContent);
	 
           

再看看消息接受者:

//在需要發送事件的地方,建立時注冊:
OttoBusManager.getInstance().register(this);
	 
//銷毀時登出:
OttoBusManager.getInstance().unRegister(this);

//接受通知,接收通知的地方最好方法寫成一樣的,這樣比較好找,其實方法名可以任意的,區分是參數:
      @Subscribe
    public void notifyBatteryChange(BatteryInfoBus bus) {
       //那麼隻要發送者發送了資料,接收者就可以收到了。
    }	
           

Otto源碼解析

可從三個步驟來分析:

1.register()

2.bus.post()

3.unregister()

1.register() 源碼

public void register(Object object) {
    if (object == null) {
      throw new NullPointerException("Object to register must not be null.");
    }
	//用于控制Bus的線程的,可以指定是any或者Main Thread
    enforcer.enforce(this);

	//用于找到Object類裡面标注了@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);
        }
      }
    }

	//一個注冊類可以有多個接受者,看Map的value,是一個Set集合就明白了。
    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);
      if (!handlers.addAll(foundHandlers)) {
        throw new IllegalArgumentException("Object already registered.");
      }
    }

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

2.bus.post() 如何發送資料的過程。

public void post(Object event) {
    if (event == null) {
      throw new NullPointerException("Event to post must not be null.");
    }
    enforcer.enforce(this);

	//找到訂閱了該事件的所有class。
    Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());

    boolean dispatched = false;
    for (Class<?> eventType : dispatchTypes) {
		//周遊該class集合,找到對應的注冊了該事件的方法,
      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();
  }
           

3. 取消注冊

public void unregister(Object object) {
    if (object == null) {
      throw new NullPointerException("Object to unregister must not be null.");
    }
    enforcer.enforce(this);

	//取消釋出者,從緩存中拿到指定釋出者,然後remove掉
    Map<Class<?>, EventProducer> producersInListener = handlerFinder.findAllProducers(object);
    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();
    }

	//取消訂閱者,方法一樣。
    Map<Class<?>, Set<EventHandler>> handlersInListener = handlerFinder.findAllSubscribers(object);
    for (Map.Entry<Class<?>, Set<EventHandler>> entry : handlersInListener.entrySet()) {
      Set<EventHandler> currentHandlers = getHandlersForEventType(entry.getKey());
      Collection<EventHandler> eventMethodsInListener = entry.getValue();

      if (currentHandlers == null || !currentHandlers.containsAll(eventMethodsInListener)) {
        throw new IllegalArgumentException(
            "Missing event handler for an annotated method. Is " + object.getClass()
                + " registered?");
      }

      for (EventHandler handler : currentHandlers) {
        if (eventMethodsInListener.contains(handler)) {
          handler.invalidate();
        }
      }
      currentHandlers.removeAll(eventMethodsInListener);
    }
  }
           

這個架構其實很簡單,将接受者注冊到一個Map中,當發送者發送消息時,周遊Map,找到具體的接受者,然後調用它的接受方法即可。