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); } } } } }
將一個事件向全部的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; } };