EventBus源码解读详细注释(6)从事件发布到事件处理,究竟发生了什么!
2016-03-21 20:45
681 查看
[EventBus源码分析(一):入口函数提纲挈领(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51802172)
[EventBus源码分析(二):register方法保存事件的订阅者列表(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51819508)
[EventBus源码分析(三):post方法发布事件【获取事件的所有订阅者,反射调用订阅者事件处理方法】(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51821143)
[EventBus源码分析(四):线程模型分析(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51832001)
[EventBus源码解读详细注释(1)register的幕后黑手](http://blog.csdn.net/wangshihui512/article/details/50914817)
[EventBus源码解读详细注释(2)MainThread线程模型分析](http://blog.csdn.net/wangshihui512/article/details/50934012)
[EventBus源码解读详细注释(3)PostThread、MainThread、BackgroundThread、Async四种线程模式的区别](http://blog.csdn.net/wangshihui512/article/details/50935729)
[EventBus源码解读详细注释(4)register时刷新的两个map](http://blog.csdn.net/wangshihui512/article/details/50938663)
[EventBus源码解读详细注释(5)事件消息继承性分析 eventInheritance含义](http://blog.csdn.net/wangshihui512/article/details/50947102)
[EventBus源码解读详细注释(6)从事件发布到事件处理,究竟发生了什么!](http://blog.csdn.net/wangshihui512/article/details/50949960)
EventBus内部存储了事件到此事件所有订阅者的map,因此post事件的时候,可以找到订阅了此事件的所有订阅者,然后根据订阅者对此事件的线程模型,在对应的线程里边,通过反射调用事件处理函数。先看EventBus里边两个重要的map
/*下边的两个map的数据都是各个线程都可以访问的,因此访问的时候要对这两个map加锁*/ /*事件到订阅者列表的map,key是事件,也就是消息处理方法的参数的Class,value是所有的订阅此事件的订阅者列表*/ private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; /*订阅者到订阅者订阅的所有事件列表的map,key是订阅者,value是该订阅者订阅的所有事件的列表*/ private final Map<Object, List<Class<?>>> typesBySubscriber;
正是这两个map存储了事件和订阅者之间对应关系的重要信息。
然后从源码的角度查看post事件的时候,事件处理方法是如何被调用的
/**EventBus维护了两个重要的map,其中一个就是事件到所有订阅了此事件的订阅者所构成的列表的map * 因此post一个事件,总能根据此map找到所有的订阅者,再根据订阅者处理此事件的线程模型,将此事件 * 分发到对应的线程,利用反射,调用订阅者对此事件的事件处理方法,完成事件的发布与处理 * Posts the given event to the event bus. * @param event*/ public void post(Object event) { /* private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() * ThreadLocal,每个线程独有,当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本, * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。*/ /*获取发布者线程的PostingThreadState,PostingThreadState封装了一些发布者线程的数据*/ PostingThreadState postingState = currentPostingThreadState.get(); /*获取该发布者线程的事件列表*/ List<Object> eventQueue = postingState.eventQueue; /*将新post的event添加到发布者线程的事件列表*/ eventQueue.add(event); /*判断标志位,判断发布者线程是否正在post*/ if (!postingState.isPosting) { /** Looper.getMainLooper(): * Returns the application's main looper, which lives in the main thread of the application. * Looper.myLooper: * Return the Looper object associated with the current thread. */ /*判断发布者线程是否为UI线程*/ postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper(); /*设置标志位,防止重复进入。假如发布者正在发布post,此时发布者又post了一个事件 * 虽然这时候不会通过 if (!postingState.isPosting)的判断 * 但是eventQueue.add(event);已经把此事件加入列表,在下边的循环中还是可以处理此event*/ postingState.isPosting = true; /*如果这时候发布者取消发布,就抛出异常*/ if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } /*循环post事件,将发布者发布的所有事件都发布出去 * 比如在某个Activity里边post了好几个事件,每次post都会将事件入队列 * */ try { while (!eventQueue.isEmpty()) { /** eventQueue.remove(0): * Removes the object at the specified location from this {@code List}. * @param location the index of the object to remove. * @return the removed object. * 取队首事件*/ postSingleEvent(eventQueue.remove(0), postingState); } } finally { /*设置标志位,不管是发布的时候出现问题,还是发布者的所有事件发布完毕,都会执行 * 设置正在发布状态为false,设置发布者线程为主线程标志为false * 如果发布者此后又post了一个事件,那么就把此事件加入队列 * 重新判断发布者线程是否为主线程*/ postingState.isPosting = false; postingState.isMainThread = false; } } }PostingThreadState封装了一些发布者线程的数据状态
/** For ThreadLocal, much faster to set (and get multiple values). */ /*封装了订阅者、事件、事件队列、和三个标志位*/ final static class PostingThreadState { /*发布者线程发布的事件列表,这里已经为列表分配了内存,所以直接调用add不会导致空指针*/ final List<Object> eventQueue = new ArrayList<Object>(); /*发布者是否正在发布事件*/ boolean isPosting; /*发布者线程是否是主线程*/ boolean isMainThread; /*发布事件的订阅者*/ Subscription subscription; /*待发布的事件*/ Object event; /*是否取消发布*/ boolean canceled; }
/** * @param event * @param postingState * @throws Error */ private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { /*获取事件的Class,所有事件的Class对应的订阅者列表在register的时候是已经保存了的*/ Class<?> eventClass = event.getClass(); /*该事件是否有订阅者的标志状态,初始化为false*/ boolean subscriptionFound = false; /*比如 A extends B implements C 发布者post(A),那么找订阅者的时候不仅要找订阅了事件A的订阅者 * 还要找订阅了B和C的订阅者*/ if (eventInheritance) { /*找到事件的所有父类和所有实现的接口*/ List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); int countTypes = eventTypes.size(); for (int h = 0; h < countTypes; h++) { Class<?> clazz = eventTypes.get(h); /*把事件的所有父类和所有实现的接口也作为事件发布出去*/ subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); } /*不考虑事件父类和实现的接口的话,那么处理起来就比较简单了*/ } else { /*将此事件发布出去*/ subscriptionFound = postSingleEventForEventType(event, postingState, eventClass); } /*此事件没有订阅者*/ if (!subscriptionFound) { if (logNoSubscriberMessages) { Log.d(TAG, "No subscribers registered for event " + eventClass); } /*如果设置了没有订阅者也照样发布事件并且该事件不是NoSubscriberEvent 或者SubscriberExceptionEvent类型 那么就发布一个特殊的事件类型*/ if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } } }
/** * @param subscription * @param event * @param isMainThread */ private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { case PostThread: /*在发布者的线程里边通过反射执行事件处理方法*/ invokeSubscriber(subscription, event); break; case MainThread: /*如果发布者线程是主线程,直接在主线程里边通过反射执行事件处理方法*/ if (isMainThread) { invokeSubscriber(subscription, event); /*如果发布者线程不是主线程,就把此事件加入主线程消息循环处理队列,在主线程中 * 通过反射调用事件处理方法*/ } else { mainThreadPoster.enqueue(subscription, event); } break; case BackgroundThread: /*如果发布者线程是主线程,那么就把此事件加入后台线程消息循环处理队列 * 通过反射调用事件处理方法,此线程模式多个事件都在一个后台线程中循环处理 * 通过队列管理多个事件*/ if (isMainThread) { backgroundPoster.enqueue(subscription, event); } else { /*发布者不在主线程,那么在发布者线程中直接通过反射调用事件处理方法*/ invokeSubscriber(subscription, event); } break; case Async: /*这种线程模式是直接开一个新的线程,调用事件处理方法,虽然看起来像是 * 通过队列在一个后台线程中循环管理多个事件,但是通过阅读源码发现并不是这样, * 而是为每一个事件都单独开辟一个线程*/ asyncPoster.enqueue(subscription, event); break; default: throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); } }四种线程模型之前已经分析过了。
相关文章推荐
- 阿里算法实习生面试回忆
- 203. Remove Linked List Elements
- JVM(2)——JVM类加载机制
- 数据持久化存储回顾
- ios三方插件
- QT学习之路————重写键盘事件
- Ubuntu14.04LTS下应用Caffe训练Cifar10错误案例分析与解决方案1
- something about Parameter Estimation (参数估计)
- Android Studio 快捷键
- 如何查看本地Git的html帮助文档
- socket编程(二)---- 简单的服务器端
- 优先队列
- 软件看门狗程序
- WebService 安卓客户端调用和服务器端搭建
- CROC 2016 - Elimination Round (Rated Unofficial Edition) E. Intellectual Inquiry 贪心 构造 dp
- 基于DDS的任意波形发生器
- Java+MySQL实现网络爬虫程序
- MySQL 入门 之 联接关键字
- 智能指针的理解
- CALayer Animation实践(一):让应用灵动起来!