subscriber和producer的扫描:
对于一个对象,如果它能产生或处理某一类型的事件,则需要将其记录起来,Otto通过HandlerFinder工具类识别这种对象。
首先看HandlerFinder接口:
interface HandlerFinder {
Map<Class<?>, EventProducer> findAllProducers(Object listener);
Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener);
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);
}
};
}
这个接口定义了两个方法来查找给定对象的事件产生方法与监听方法。对于找到的事件产生对象保存在一个map里, map的key是事件的类型, value是一个包装对象EventProducer, 从这里可以看出,对于一种事件类型,一个对象最多允许有一个事件产生方法; 对于事件监听, 一个对象则可以有多个方法对同一类型事件进行监听。
扫描实现:
上述HandlerFinder接口在功能上实际是由AnnotatedHandlerFinder实现的(虽然没显示implement);
PRODUCER_CACHE 的类型是这样的 Map<ProducerClass, Map<事件类型, 方法> > ,
SUBSCRIBER_CACHE的类型: Map< SubscriberClass, Map< 事件类型,Set<方法> > >.
因为一个类对某一类型事件只能有一个产生方法, 但是,一个类对某一类型事件可以有多个监听方法。
loadAnnotatedMethods(Class<?> )扫描一个类,将其带有标注的方法及对应的事件类型放入相应的cache。
注意区分listener 与listenerClass, 前者是一个普通的对象, 后者是listener的 类型(Class)。
final class AnnotatedHandlerFinder {
private static final Map<Class<?>, Map<Class<?>, Method>> PRODUCERS_CACHE = new HashMap<Class<?>, Map<Class<?>, Method>>();
private static final Map<Class<?>, Map<Class<?>, Set<Method>>> SUBSCRIBERS_CACHE = new HashMap<Class<?>, Map<Class<?>, Set<Method>>>();
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);
}
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);
}
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;
}