0 使用手冊:http://square.github.io/otto/
基本原理
使用@Subscribe註解一個Event事件處理方法和@Produce註解一個Event事件生成方法,在register的時候利用反射將這些方法按照Event類型保存在Map中,當使用Bus.post(Object event)時,在Map中找到event對應的事件處理方法,然後分別調用一遍,來實現事件總線的功能。
數據結構分析
0.1 ThreadEnforcer:該類用於對調用線程進行檢查,若不滿足條件則跑出異常。例如:
ThreadEnforcer MAIN = new ThreadEnforcer() {
@Override public void enforce(Bus bus) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("Event bus " + bus + " accessed from non-main thread " + Looper.myLooper());
}
}
};
0.2 EventProducer:該類表示一個註解了Produce的方法。target字段表示register時的對象,method字段是該方法的反射。需要產生event對象時,直接調用method.invoke(target)即可。
0.3 EventHandler:該類表示一個註解了Subscribe的方法。同樣target字段表示register時的對象,method字段是該方法的反射。有post event對象時,直接調用method.invoke(target, event)即可。
0.4 DeadEvent: 如果post一個event事件時,沒有對應的subscribe的方法,則post該DeadEvent對象。source字段表示是由哪個對象post出來的,event表示沒有subscribe的那個事件。
0.5 AnnotatedHandlerFinder:該類用於在register和unregister時,查找這個對象的所有Subscribe和Produce方法。
0.6 Bus:事件總線類,該類用來註解了Produce和Subscribe的對象註冊到總線上,需要時使用該總線post一個event事件,即可調用註解了Subscribe的方法。
1 初始化
手冊建議(不強制)單例模式使用Bus。代碼如下:
public final class BusProvider {
private static final Bus BUS = new Bus();
public static Bus getInstance() {
return BUS;
}
private BusProvider() {
// No instances.
}
}
初始化過程中,初始化ThreadEnforcer,HandlerFinder,前者用於設置調用post,register,unregister是否檢查調用線程,確保是主線程;後者用於register時在找出所有註解有Subsribe和Produce的方法。
Bus(ThreadEnforcer enforcer, String identifier, HandlerFinder handlerFinder) {
this.enforcer = enforcer;
this.identifier = identifier;
this.handlerFinder = handlerFinder;
}
2 register
public void register(Object object) {
if (object == null) {
throw new NullPointerException("Object to register must not be null.");
}
//檢查調用線程
enforcer.enforce(this);
//找出object對象的所有標記有Produce的方法,爲每一個方法生成一個<Class<?>,EventProducer>,其中Class<?>爲方法返回值,EventProducer表示註解的方法。然後檢查Class<?>的Produce方法是否唯一,然後爲每一個Class<?>調用對應Subscribe方法
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);
}
}
}
//找出object對象的所有標記有Subscribe的方法,爲每一個方法生成一個<Class<?>,Set<EventHandler>>,其中Class<?>爲方法參數,有且僅有一個,EventHandler表示註解Subscribe的方法。然後檢查Class<?>是否已經註冊過,然後爲每一個Class<?>調用對應已經註冊Produce方法生成一個event,使用該event調用對應的所有EventHandler
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);
}
}
}
}
}
3 unregister
public void unregister(Object object) {
if (object == null) {
throw new NullPointerException("Object to unregister must not be null.");
}
enforcer.enforce(this);
//找出所有註解有Produce的方法,將每一個方法從Map中移除
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();
}
//找出所有註解有Subscribe的方法,將每一個方法從Map中移除
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);
}
}
4 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());
boolean dispatched = false;
//根據event的類型將event分成event類型,event類型的父類型....並找出所有Subscribe的方法,即EventHandler //,爲每一個EventHandler生成一個
//EventWithHandler對象,放入處理隊列eventsToDispatch中,分別調用一遍,如果沒有Subscribe該Event的方法 //則post一個DeadEvent。 // for (Class<?> eventType : dispatchTypes) {
Set<EventHandler> wrappers = getHandlersForEventType(eventType);
if (wrappers != null && !wrappers.isEmpty()) {
dispatched = true;
for (EventHandler wrapper : wrappers) {
//放入處理隊列eventsToDispatch中
enqueueEvent(event, wrapper);
}
}
}
if (!dispatched && !(event instanceof DeadEvent)) {
post(new DeadEvent(this, event));
}
dispatchQueuedEvents();
}
4.1 dispatchQueuedEvents
該函數重點分析的原因是該函數的實現方式,避免了函數重入和處理亂序的問題,值得借鑑。
protected void dispatchQueuedEvents() {
// don't dispatch if we're already dispatching, that would allow reentrancy and out-of-order events. Instead, leave
// the events to be dispatched after the in-progress dispatch is complete.
//當前線程如果在處理過程中又post一個event,則會重入該函數,並且後post的事件會先處理。這裏爲了避免這個情況,利用一個隊列,將post的事件放入隊列中, //然後按入隊的順序處理這些事件。 if (isDispatching.get()) {
return;
}
isDispatching.set(true);
try {
while (true) {
EventWithHandler eventWithHandler = eventsToDispatch.get().poll();
if (eventWithHandler == null) {
break;
}
if (eventWithHandler.handler.isValid()) {
dispatch(eventWithHandler.event, eventWithHandler.handler);
}
}
} finally {
isDispatching.set(false);
}
}
5 AnnotatedHandlerFinder類分析
該類有兩個靜態域:PRODUCERS_CACHE和SUBSCRIBERS_CACHE,都是Map類型,這兩個域用於緩存一個對象上所有註解了@Subscribe和@Produce的方法,其中Key爲調用Bus.register(Object object)方法和Bus.unregister(Object object)方法時object對象的類型;Value也是一個Map,Value Map的Key爲註解方法的事件類型,對應註解@Subscribe的方法是方法參數,註解@Produce的方法是方法返回值,Value Map的Value是方法的反射類型Method。其中對於一個Event事件@Subscribe方法可能會有多個,但是@Produce方法只會有一個,所有前者用Set<Method>保存,後者用Method保存。
private static void loadAnnotatedMethods(Class<?> listenerClass) {
Map<Class<?>, Set<Method>> subscriberMethods = new HashMap<Class<?>, Set<Method>>();
Map<Class<?>, Method> producerMethods = new HashMap<Class<?>, Method>();
//遍歷每一個method,進行必要的判斷,
//如果註解了@Subscribe則保證只有一個參數,方法是Public的,
//如果是註解了@Produce則保證一定是註解在類上,方法是Public的,返回值不是void類型.
//然後按照event類型將所有@Subscribe方法保存在一個Map中,@Produce方法保存在另外一個Map中,
//最後按照listenerClass,即register(Object object)時object的類型分別保存在PRODUCERS_CACHE
//和SUBSCRIBERS_CACHE中。
for (Method method : listenerClass.getDeclaredMethods()) {
// The compiler sometimes creates synthetic bridge methods as part of the
// type erasure process. As of JDK8 these methods now include the same
// annotations as the original declarations. They should be ignored for
// subscribe/produce.
if (method.isBridge()) {
continue;
}
if (method.isAnnotationPresent(Subscribe.class)) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1) {
throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation but requires "
+ parameterTypes.length + " arguments. Methods must require a single argument.");
}
Class<?> eventType = parameterTypes[0];
if (eventType.isInterface()) {
throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation on " + eventType
+ " which is an interface. Subscription must be on a concrete class type.");
}
if ((method.getModifiers() & Modifier.PUBLIC) == 0) {
throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation on " + eventType
+ " but is not 'public'.");
}
Set<Method> methods = subscriberMethods.get(eventType);
if (methods == null) {
methods = new HashSet<Method>();
subscriberMethods.put(eventType, methods);
}
methods.add(method);
} else if (method.isAnnotationPresent(Produce.class)) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 0) {
throw new IllegalArgumentException("Method " + method + "has @Produce annotation but requires "
+ parameterTypes.length + " arguments. Methods must require zero arguments.");
}
if (method.getReturnType() == Void.class) {
throw new IllegalArgumentException("Method " + method
+ " has a return type of void. Must declare a non-void type.");
}
Class<?> eventType = method.getReturnType();
if (eventType.isInterface()) {
throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType
+ " which is an interface. Producers must return a concrete class type.");
}
if (eventType.equals(Void.TYPE)) {
throw new IllegalArgumentException("Method " + method + " has @Produce annotation but has no return type.");
}
if ((method.getModifiers() & Modifier.PUBLIC) == 0) {
throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType
+ " but is not 'public'.");
}
if (producerMethods.containsKey(eventType)) {
throw new IllegalArgumentException("Producer for type " + eventType + " has already been registered.");
}
producerMethods.put(eventType, method);
}
}
PRODUCERS_CACHE.put(listenerClass, producerMethods);
SUBSCRIBERS_CACHE.put(listenerClass, subscriberMethods);
}
/** This implementation finds all methods marked with a {@link Produce} annotation. */
static Map<Class<?>, EventProducer> findAllProducers(Object listener) {
final Class<?> listenerClass = listener.getClass();
Map<Class<?>, EventProducer> handlersInMethod = new HashMap<Class<?>, EventProducer>();
if (!PRODUCERS_CACHE.containsKey(listenerClass)) {
loadAnnotatedMethods(listenerClass);
}
//從PRODUCERS_CACHE中找出出listener類所有的@Produce方法,爲每一個方法生成一個
//EventProducer,放入handlersInMethod中,handlersInMethod中的Key爲事件類型,
//即@Produce方法的返回值類型
Map<Class<?>, Method> methods = PRODUCERS_CACHE.get(listenerClass);
if (!methods.isEmpty()) {
for (Map.Entry<Class<?>, Method> e : methods.entrySet()) {
EventProducer producer = new EventProducer(listener, e.getValue());
handlersInMethod.put(e.getKey(), producer);
}
}
return handlersInMethod;
}
/** This implementation finds all methods marked with a {@link Subscribe} annotation. */
static Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) {
Class<?> listenerClass = listener.getClass();
Map<Class<?>, Set<EventHandler>> handlersInMethod = new HashMap<Class<?>, Set<EventHandler>>();
if (!SUBSCRIBERS_CACHE.containsKey(listenerClass)) {
loadAnnotatedMethods(listenerClass);
}
//SUBSCRIBERS_CACHE找出所有的@Subscribe方法,爲每一個方法生成一個
//EventHandler,放入handlersInMethod中,handlersInMethod中的Key爲事件類型,
//即@Subscribe方法的參數類型
Map<Class<?>, Set<Method>> methods = SUBSCRIBERS_CACHE.get(listenerClass);
if (!methods.isEmpty()) {
for (Map.Entry<Class<?>, Set<Method>> e : methods.entrySet()) {
Set<EventHandler> handlers = new HashSet<EventHandler>();
for (Method m : e.getValue()) {
handlers.add(new EventHandler(listener, m));
}
handlersInMethod.put(e.getKey(), handlers);
}
}
return handlersInMethod;
}