版權聲明:本文爲博主原創文章,未經博主允許不得轉載。
本文轉載自:http://blog.csdn.net/itachi85/article/details/53965231?ref=myread
相關文章
Android事件總線(一)EventBus3.0用法全解析
Android事件總線(二)EventBus3.0源碼解析
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);
}
- 1
- 2
- 3
- 1
- 2
- 3
這個DEFAULT_IDENTIFIER是一個字符串”default”,this調用了Bus類的另一個構造函數:
public Bus(String identifier) {
this(ThreadEnforcer.MAIN, identifier);
}
- 1
- 2
- 3
- 1
- 2
- 3
ThreadEnforcer.MAIN意味着默認在主線程中調度事件,再往裏看this又調用了什麼,如下所示。
public Bus(ThreadEnforcer enforcer, String identifier) {
this(enforcer, identifier, HandlerFinder.ANNOTATED);
}
- 1
- 2
- 3
- 1
- 2
- 3
第一個參數我們提到了,就是事件調度的簡稱,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;
}
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
這個是最終調用的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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
註釋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);
}
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
從上面的代碼的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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
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
}
}
}
...
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
調用完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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
註釋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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
取消註冊分爲兩部分,一部分是訂閱者取消註冊,另一部分是發佈者取消註冊。這兩部分的代碼類似,因此,上面的代碼只列出了發佈者取消註冊的代碼。在註釋1處得到所有使用@Produce註解的方法,並遍歷這些方法,調用註釋2處的代碼從緩存中清除所有和傳進來的註冊類相關的發佈者,來完成發佈者的取消註冊操作。