Otto的使用和源码分析
2015-08-11 13:53
274 查看
Otto
Otto是square的一个event bus实现。Event bus是一款针对Android优化的发布/订阅事件总线,主要功能是替代Intent、Handler、BroadCast
在Activity、Fragment、Service、Thread之间传递消息。其优点是开销小,代码更优雅,以及
将发送者和接收者解耦。
下载
在Android studio的module级别的build.gradle中dependencies下加入compile 'com.squareup:otto:1.3.8'
使用
1.新建一个Bus实例,建议使用单例。java Bus bus = new Bus();
2.事件发布是非常重要的,因为它可以通知相应事件的订阅者某个动作已经发生。任何的类实例都可以
通过Bus发布事件,并且只有订阅了该事件的订阅者才会收到相应通知。
通过post方法发布一个新的事件
java bus.post(new AnswerAvailableEvent(42));
除此之外,还有另外一种方法可以发布事件,这种形式会在Bus调用register方法时立即发布事件。
java @Produce public AnswerAvailableEvent produceAnswer() { // Assuming 'lastAnswer' exists. return new AnswerAvailableEvent(this.lastAnswer); }
在方法级别上添加@Produce注解,方法的访问权限一定得是public的,并且其返回值类型是所发布
的事件类型。
这种事件发布形式还必需得在类实例中注册Bus实例
java bus.register(this);
否则这个事件是无法让其订阅者接收到事件通知的。
3.订阅一个事件,你需要在方法级别上添加一个@Subscribe的注解。这个方法只能带有一个参数,
并且类型是你需要的订阅事件类型。
订阅一个事件,需要这样做
java @Subscribe public void answerAvailable(AnswerAvailableEvent event) { // TODO: React to the event somehow! }
需要注意的是,上面的方法其访问权限一定得是public的,其他无限制。
为了能够接收到事件,类实例需要注册Bus。通过下面方式注册
java bus.register(this);
我们可以在适当的时候调用unregister方法取消Bus的注册
java bus.unregister(this);
我们可以在Activity和Fragment的OnResume方法中注册Bus,然后在OnPause方法中取消注册。
4.默认的,新建的Bus是在主线程上活动的。
java Bus bus1 = new Bus(); Bus bus2 = new Bus(ThreadEnforcer.MAIN);
上面两句代码是等价的。
你还可以实例化一个在任何线程都可以活动的Bus,
java Bus bus3 = new Bus(ThreadEnforcer.ANY);
5.对于上面的使用方法,我是参照官方文档做一个大概的说明。大家可以使用git clone下官方提供
的sample研究具体的使用方法。
链接: https://github.com/square/otto
源码分析
Otto的源码只有九个类,阅读起来还是很容易理解的。先看@Produce、@Subscribe这两个注解的定义。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Produce { } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Subscribe { }
可以看出这两个注解都是在jvm运行时可获得的,并且都是作用在方法级别上。
再来看ThreadEnforcer、HandlerFinder两个接口。
public interface ThreadEnforcer { /** * 强制bus在某个确定的线程 */ void enforce(Bus bus); /** A {@link ThreadEnforcer} that does no verification. */ ThreadEnforcer ANY = new ThreadEnforcer() { @Override public void enforce(Bus bus) { // Allow any thread. } }; /** A {@link ThreadEnforcer} that confines {@link Bus} methods to the main thread. */ 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()); } } }; }
ThreadEnforcer里面提供了两个默认的实现,其中我们新创建的Bus实例是默认使用Android的主线程的。
/** Finds producer and subscriber methods. */ 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); } }; }
HandlerFinder是用于查找使用了@Produce和@Subscribe的方法及事件类型的的。从方法定义就可以看出,一个
类中只能存在一个通过@Produce发布事件的方法,却可以存在多个使用@Subscribe的方法,即事件订阅者。
同样的,HandlerFinder里面也提供了一个默认的实现,委派AnnotatedHandlerFinder进行具体的操作。
其中,EventProducer的代码实现如下
class EventProducer { /** Object sporting the producer method. */ final Object target; /** Producer method. */ private final Method method; EventProducer(Object target, Method method) { if (target == null) { throw new NullPointerException("EventProducer target cannot be null."); } if (method == null) { throw new NullPointerException("EventProducer method cannot be null."); } this.target = target; this.method = method; /** 抑制java对修饰符访问权限的检查,提高jdk的反射效率 */ method.setAccessible(true); ... } /** * 通过反射调用方法 */ public Object produceEvent() throws InvocationTargetException { if (!valid) { throw new IllegalStateException(toString() + " has been invalidated and can no longer produce events."); } try { return method.invoke(target); } catch (IllegalAccessException e) { throw new AssertionError(e); } catch (InvocationTargetException e) { if (e.getCause() instanceof Error) { throw (Error) e.getCause(); } throw e; } } // 重写toString()、hashCode()、equals()方法 }
EventHandler类的代码也差不多。
再来看看AnnotatedHandlerFinder到底干了哪些事。
final class AnnotatedHandlerFinder { /* * 用于保存使用了@Produce注解的类及方法,其中map的键是监听类,值是一个map,值的map的 * 键是事件类型,值是方法 */ private static final ConcurrentMap<Class<?>, Map<Class<?>, Method>> PRODUCERS_CACHE = new ConcurrentHashMap<Class<?>, Map<Class<?>, Method>>(); /** 用于保存使用了@Subscribe注解的类及方法 */ private static final ConcurrentMap<Class<?>, Map<Class<?>, Set<Method>>> SUBSCRIBERS_CACHE = new ConcurrentHashMap<Class<?>, Map<Class<?>, Set<Method>>>(); /** 加载使用了@Produce注解的类及方法 */ private static void loadAnnotatedProducerMethods(Class<?> listenerClass, Map<Class<?>, Method> producerMethods) { Map<Class<?>, Set<Method>> subscriberMethods = new HashMap<Class<?>, Set<Method>>(); loadAnnotatedMethods(listenerClass, producerMethods, subscriberMethods); } /** 加载使用了@Subscribe注解的类及方法 */ private static void loadAnnotatedSubscriberMethods(Class<?> listenerClass, Map<Class<?>, Set<Method>> subscriberMethods) { Map<Class<?>, Method> producerMethods = new HashMap<Class<?>, Method>(); loadAnnotatedMethods(listenerClass, producerMethods, subscriberMethods); } /** * 加载所有使用了@Produce和@Subscribe注解的方法 */ 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>(); 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."); } /** 方法返回类型是否为Void.class判断 */ 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'."); } /** 判断此类事件是否已经由@Produce发布过 */ 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); } /** 查找所有的@Produce */ 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); /** 如果缓存中不存在 */ 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; } /** 查找所有的@Subscribe */ static Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) { ... } private AnnotatedHandlerFinder() { // No instances. } }
阅读AnnotatedHandlerFinder之后,可以很清楚地知道它主要是负责查找指定类中带有@Produce
和@Subscribe注解的方法,并且把相应的事件类型放到相应的缓存中。
其中HandlerFinder的默认实现ANNOTATED就是使用了AnnotatedHandlerFinder.findAllProducers(listener)
和AnnotatedHandlerFinder.findAllSubscribers(listener)来完成具体的注解查找工作的。
最后只剩下最重要的Bus类了。
因为我们使用Otto是从在Activity或Fragment的OnResume方法中进行register()开始的,所有我们
看看register()到底干了什么事。
public void register(Object object) { if (object == null) { throw new NullPointerException("Object to register must not be null."); } /** 确认所在线程 */ enforcer.enforce(this); /** 查找所有的@Produce */ Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object); for (Class<?> type : foundProducers.keySet()) { /** 判断是否当前类已经存在一个使用@Produce的方法 */ 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); } } } /** 查找所有的@Subscribe */ 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); } } } } }
到了这里,我们已经很清楚了,register方法主要是查找所有的@Produce和@Subscribe并且进行事件
分发给handler处理。
private void dispatchProducerResultToHandler(EventHandler handler, EventProducer producer) { Object event = null; try { /** 通过反射调用方法,前面已经在EventProducer分析过,发布@Produce的事件 */ event = producer.produceEvent(); } catch (InvocationTargetException e) { throwRuntimeException("Producer " + producer + " threw an exception.", e); } if (event == null) { return; } /** 再次分发事件 */ dispatch(event, handler); } protected void dispatch(Object event, EventHandler wrapper) { try { /** 通过反射调用方法,前面已经在EventHandler分析过,这里就是接收到事件通知之后执行具体的操作,执行@Subscribe的方法 */ wrapper.handleEvent(event); } catch (InvocationTargetException e) { throwRuntimeException( "Could not dispatch event: " + event.getClass() + " to handler " + wrapper, e); } }
至于unregister和register方法则是相反的操作,移除当前类及方法的监听。
当我们调用post发布事件又发生了什么事呢?
下面我们来看看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; for (Class<?> eventType : dispatchTypes) { Set<EventHandler> wrappers = getHandlersForEventType(eventType); if (wrappers != null && !wrappers.isEmpty()) { dispatched = true; for (EventHandler wrapper : wrappers) { /** 把事件添加进队列 */ enqueueEvent(event, wrapper); } } } /** 没有订阅者的事件没有被分发,被封装成DeadEvent再次post出去 */ if (!dispatched && !(event instanceof DeadEvent)) { post(new DeadEvent(this, event)); } /** 逐一分发事件队列的事件方法 */ dispatchQueuedEvents(); } protected void enqueueEvent(Object event, EventHandler handler) { eventsToDispatch.get().offer(new EventWithHandler(event, handler)); } 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); } }
最后,整个Otto的源码分析过程就完成了。
相关文章推荐
- Objective-C Runtime 运行时
- JQuery: 微博演示
- 修改mysql默认字符集的方法
- c# workwith .ini file
- java模拟HTTP请求
- java类过滤器,防止页面sql注入
- 在最能拼搏的年纪选择了稳定
- Linux消息队列通讯编程
- 国内主要工作流厂商分析--ronghao
- Linux安装ipython
- bind禁用ipv6方法
- git merge 和 git merge --no-ff
- 1020. 月饼 (25)
- nmap 使用注意事项
- [技巧篇]09.Struts2豁然开朗的一些配置[记得要看哟]
- Oracle 12C -- sequence的新特性
- linux下 常见bug总结
- LeetCode - Read N Characters Given Read4 II - Call multiple times
- 常用简体汉字unicode编码(3500个)
- (visual)c++ 内存分配