Android事件總線(四)源碼解析otto
前言
上一篇文章中講到了otto的用法,這一篇我們來講一下otto的源碼。可能有人覺得otto過時了,但是通過源碼我們學習的是高手設計otto時的設計理念,這種設計理念是不過時的。
otto各個類的作用
如圖所示,otto的源碼并不多,主要的類的功能如下:
- Produce、Subscribe:發布者和訂閱者注解類。
- Bus:事件總線類,用來注冊和取消注冊,維護發布-訂閱模型,并處理事件調度分發。
- HandlerFinder、AnnotatedHandlerFinder:用來查找發布者和訂閱者。
- EventProducer、EventHandler:分別封裝發布者和訂閱者的數據結構。
otto構造函數
在使用otto時,首先要創建Bus類,Bus類的構造函數如下所示。
public Bus() { this(DEFAULT_IDENTIFIER); }
這個DEFAULT_IDENTIFIER是一個字符串”default”,this調用了Bus類的另一個構造函數:
public Bus(String identifier) { this(ThreadEnforcer.MAIN, identifier); }
ThreadEnforcer.MAIN意味著默認在主線程中調度事件,再往里看this又調用了什么,如下所示。
public Bus(ThreadEnforcer enforcer, String identifier) { this(enforcer, identifier, HandlerFinder.ANNOTATED); }
第一個參數我們提到了,就是事件調度的簡稱,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; }
這個是最終調用的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 ... }
注釋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); } };
從上面的代碼的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; }
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 } } } ... }
調用完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 }
注釋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 } ... }
取消注冊分為兩部分,一部分是訂閱者取消注冊,另一部分是發布者取消注冊。這兩部分的代碼類似,因此,上面的代碼只列出了發布者取消注冊的代碼。在注釋1處得到所有使用@Produce注解的方法,并遍歷這些方法,調用注釋2處的代碼從緩存中清除所有和傳進來的注冊類相關的發布者,來完成發布者的取消注冊操作。

浙公網安備 33010602011771號