Otto有何用处,什么时候使用otto,当你组件存在交互的时候,比如Activity和Activity,Activity和Fragment,Activity和Service,如果用最原始的方法交互的话,会显得代码沉余显得乱,而且不利于阅读,那么这时候就可以用Otto了,就像用eventBus一样。Otto定义了两个最重要的角色
1:事件生产者
2:事件订阅者
大体的意思就是客户端主动生产事件,看代码,对就是他
BusProvider.getInstance().post(produceLocationEvent());
produceLocationEvent()这句话被标记了一个@Produce注解,表示这个事件是被生产出来的
@Produce
public LocationChangedEvent produceLocationEvent() {
// Provide an initial value for location based on the last known
// position.
return new LocationChangedEvent(lastLatitude, lastLongitude);
}
生产完事件之后呢?当然是把事件传递给订阅者了,那么也就是生产者生产事件后,将事件放入队列中,然后检查队列的事件有没有订阅者订阅,如果订阅的话就将事件传给订阅者。下面是订阅者的注解 @Subscribe
@Subscribe public void onLocationChanged(LocationChangedEvent event) {
// Stop existing download, if it exists.
if (downloadTask != null) {
downloadTask.cancel(true);
}
// Trigger a background download of an image for the new location.
downloadTask = new DownloadTask();
downloadTask.execute(String.format(URL, event.lat, event.lon));
}
官方例子提供了
Activity和
Frament的交互,那么下面顺着例子一步一步的走,首先不管订阅还是生产都需要将当前的对象注册进组件,那么从注册开始
BusProvider.getInstance().register(this);
当前对象带有生产者和订阅者的注解,那么想让注解生效必须实现注册,那么接着看注册给我们实现了什么
public void register(Object object) {
if (object == null) {
throw new NullPointerException("Object to register must not be null.");
}
//检查是否是主线程,不是抛异常
enforcer.enforce(this);
//此处的handlerFinder传给AnnotatedHandlerFinder去查询
Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);
for (Class<?> type : foundProducers.keySet()) {
//此处type是生产者返回值的类型
final EventProducer producer = foundProducers.get(type);
//如果集合中没有存储返回null,防止重复存储
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);
}
}
}
/**
* 查询所有的订阅者
*/
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);
}
}
}
}
}
这个方法的代码比较多,那么一点一点的分析,首先看一下
enforcer是什么?
public interface ThreadEnforcer {
/**
* Enforce a valid thread for the given {@code bus}. Implementations may throw any runtime exception.
*
* @param bus Event bus instance on which an action is being performed.
*/
void enforce(Bus bus);
/** A {@link ThreadEnforcer} that does no verification. */
ThreadEnforcer ANY = new ThreadEnforcer() {
@Override public void enforce(Bus bus) {
// Allow any thread.
}
};
奥,他是一个接口,那么Bus里面的 ThreadEnforcer是哪一个实现类呢?
public Bus(String identifier) {
this(ThreadEnforcer.MAIN, identifier);
}
bus的不带参构造函数,默认调用带参构造函数,也就是给了一个默认实现类
/**
* 默认
*/
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());
}
}
};
这个默认实现接口的类检查注册是不是在主线程,不在主线程则抛异常。当然我们可以扩展到子线程里面执行。
Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);
接下来就是这句根据传过来的对象查询事件生产者,进去看看什么鬼
/**
* 默认的实现类
*/
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);
}
};
查找handler的类也是采用的默认实现类,而真正进行查询的是 AnnotatedHandlerFinder的静态方法,从英文意思也大概可以猜测到,此方法采用了反射获得注解的信息,ok进入
static Map<Class<?>, EventProducer> findAllProducers(Object listener) {
//反射得到class
final Class<?> listenerClass = listener.getClass();
//新创建一个集合
Map<Class<?>, EventProducer> handlersInMethod = new HashMap<Class<?>, EventProducer>();
/**
* 从缓存中取集合如果有的话
*/
Map<Class<?>, Method> methods = PRODUCERS_CACHE.get(listenerClass);
if (null == methods) {
methods = new HashMap<Class<?>, Method>();
loadAnnotatedProducerMethods(listenerClass, methods);
}
/*
* 将当前事件注册进去
*/
if (!methods.isEmpty()) {
for (Map.Entry<Class<?>, Method> e : methods.entrySet()) {
//添加EventProducer生产者
EventProducer producer = new EventProducer(listener, e.getValue());
handlersInMethod.put(e.getKey(), producer);
}
}
return handlersInMethod;
}
首先通过对象获取class,然后查询生产者缓存池里面有没有,没有的话就,创建一个存放方法的子集合
methods = new HashMap<Class<?>, Method>();
loadAnnotatedProducerMethods(listenerClass, methods);
并开始解析注解,前面添加的注解终于要用到了,看到这可以了解到此框架把设计模式写的多么出神入化了,单一职责,一个类只负责自己的工作,面向对象:一个类可以有多个方法,所以
PRODUCERS_CACHE保存的是
HashMap<Class<?>, Method>(),
另外还用了享元模式,减少垃圾回收器的频繁操作,提高运行速度。而Bus类采用了外观模式
所有的操作以他为入口类,协调其他类工作。那么接着进入 loadAnnotatedProducerMethods
private static void loadAnnotatedProducerMethods(Class<?> listenerClass,
Map<Class<?>, Method> producerMethods) {
Map<Class<?>, Set<Method>> subscriberMethods = new HashMap<Class<?>, Set<Method>>();
loadAnnotatedMethods(listenerClass, producerMethods, subscriberMethods);
}
吆喝,这个过渡方法又创建了 Map<Class<?>, Set<Method>> subscriberMethods = new HashMap<Class<?>, Set<Method>>();专门存放订阅者方法的类,那么现在已经说明一个类即可以是事件生产者又可以是事件订阅者。
/**
* 添加所有注解的方法进集合
*/
private static void loadAnnotatedMethods(Class<?> listenerClass,
Map<Class<?>, Method> producerMethods, Map<Class<?>, Set<Method>> subscriberMethods) {
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.");
}
/**
* 注解的方法必须是public的
*/
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>();
//将methond
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.");
}
/**
* 必须是public的
*/
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);
}
通过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.");
}
/**
* 限定修饰符必须是public
*/
if ((method.getModifiers() & Modifier.PUBLIC) == 0) {
throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType
+ " but is not 'public'.");
}
现在总结如下, otto给我们的事件生产者指定了这些规则:
1:事件生产者的方法必须有没有参数
2:事件生产者的方法必须有返回值且返回值必须是具体的对象
3:生产者方法修饰符必须是public
如果都满足条件的话 producerMethods.put(eventType, method),以返回值类型作为key值,以方法method作为value加入集合,其实返回值类型就是事件的类型,下面看一下事件订阅者
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.");
}
/**
* 注解的方法必须是public的
*/
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>();
//将methond
subscriberMethods.put(eventType, methods);
}
//将方法储存到集合
methods.add(method);
}
1:订阅者的方法只能有个参数,这个参数就是事件
2:方法修饰符同样是public
接下来同样将订阅者事件方法放入集合中,这里还有一个点要注意,事件必须是具体的对象,不能是object,因为有如下判断
if (method.isBridge()) {
continue;
}
如果是 object则不注册。接下来执行
/*
* 将当前事件注册进去
*/
if (!methods.isEmpty()) {
for (Map.Entry<Class<?>, Method> e : methods.entrySet()) {
//添加EventProducer生产者
EventProducer producer = new EventProducer(listener, e.getValue());
handlersInMethod.put(e.getKey(), producer);
}
}
查找到有方法注解的话,那么集合里会有数据,那么遍历集合,创建真正执行事件生产的类 EventProducer, 可见EventProducer存放了当前的注册的对象还有方法,当然反射调用方法的两个前提是1、有当前对象,2、有反射的method的对象,最终将他放入 handlersInMethod集合,key同样是事件的类型,最终返回 handlersInMethod集合
for (Class<?> type : foundProducers.keySet()) {
//此处type是生产者返回值的类型
final EventProducer producer = foundProducers.get(type);
//如果集合中没有存储返回null,防止重复存储
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);
}
}
}
接下来遍历返回的集合,判断 producersByType集合是否有生产者的注册如果有的话,就抛异常,也就是说生产某个事件的类型只能有一款,然后判断 handlersByType中是否有该事件的订阅者,有的话通知订阅者,也就是假如先注册的同一个事件A的订阅者,此时还没有注册事件A的生产者,如果一旦注册了事件A的生产者,那么会回调订阅者的方法。
/**
* 查询所有的订阅者
*/
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);
}
}
}
}
接下来又查询所有的订阅者,流程和查询生产者类似,不再阐述!最终执行订阅事件的是 EventHandler类,被存入集合
接下来看生产事件后,怎么传给订阅者的
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);
}
}
}
/**
* 如果没有找到的话并且事件不属于DeadEvent事件,执行DeadEvent事件
*/
if (!dispatched && !(event instanceof DeadEvent)) {
//递归调用,最终啥也不执行
post(new DeadEvent(this, event));
}
//开始分发事件
dispatchQueuedEvents();
}
先看
flattenHierarchy方法,此方法的作用是查找累的树形结构并把它放在集合中,look
Set<Class<?>> flattenHierarchy(Class<?> concreteClass) {
Set<Class<?>> classes = flattenHierarchyCache.get(concreteClass);
if (classes == null) {
Set<Class<?>> classesCreation = getClassesFor(concreteClass);
classes = flattenHierarchyCache.putIfAbsent(concreteClass, classesCreation);
if (classes == null) {
classes = classesCreation;
}
}
return classes;
}
这里又用了一个集合储存事件class和他的所有超类,接着进入这个方法 getClassesFor(concreteClass);
/**
* 将目标类的所有超类全部取出放在 Set<Class<?>>返回
* @param concreteClass
* @return
*/
private Set<Class<?>> getClassesFor(Class<?> concreteClass) {
List<Class<?>> parents = new LinkedList<Class<?>>();
Set<Class<?>> classes = new HashSet<Class<?>>();
parents.add(concreteClass);
while (!parents.isEmpty()) {
Class<?> clazz = parents.remove(0);
classes.add(clazz);
Class<?> parent = clazz.getSuperclass();
if (parent != null) {
parents.add(parent);
}
}
return classes;
}
很明显,循环读取父类class,如果有父类的话,将他放入 classes集合并返回,接下来就是遍历集合,取出所有的class进行匹配
Set<EventHandler> getHandlersForEventType(Class<?> type) {
return handlersByType.get(type);
}
检查订阅者集合中是否有订阅了当前事件的订阅者,有的话,将它放入队列
*/
protected void enqueueEvent(Object event, EventHandler handler) {
eventsToDispatch.get().offer(new EventWithHandler(event, handler));
}
此处的 eventsToDispatch为 ConcurrentLinkedQueue链表队列
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.
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);
}
}
那么接下来就是遍历链表队列分发事件了,如果队列中有事件订阅者,并且是可以接收数据的, dispatch(eventWithHandler.event, eventWithHandler.handler)开始执行订阅的事件方法
protected void dispatch(Object event, EventHandler wrapper) {
try {
wrapper.handleEvent(event);
} catch (InvocationTargetException e) {
throwRuntimeException(
"Could not dispatch event: " + event.getClass() + " to handler " + wrapper, e);
}
}
event是我们传过来的事件对象,那么接下来反射执行订阅者的方法
/**
* 处理事件
*/
public void handleEvent(Object event) throws InvocationTargetException {
if (!valid) {
throw new IllegalStateException(toString()
+ " has been invalidated and can no longer handle events.");
}
try {
method.invoke(target, event);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Error) {
throw (Error) e.getCause();
}
throw e;
}
}
也就是这个方法
@Subscribe
public void onLocationChanged(LocationChangedEvent event) {
// Stop existing download, if it exists.
if (downloadTask != null) {
downloadTask.cancel(true);
}
好了产生事件并把事件分给订阅者的流程就结束了,从中得到一个关键点,生产同一个事件的生产者只有一个,而订阅者可以有多个,也就是生产者和订阅者是1对多的关系。最后就是解绑订阅者和事件生产者了
/**
* 取消注册
* @param object
*/
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);
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();
}
/**
* 找到所有的订阅者清除订阅者集合
*/
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);
}
}
这个方法看起来很多,但是逻辑没有那么复杂,就是检查缓存集合中是否有当前对象绑定的事件生产者和消费者,有的话从 handlersByType集合或producersByType集合中清除,到此otto框架就分析完了,现在你可以尝试一下自己写一个eventbus实现自己组件之间的交互。