EventBus源码解读详细注释(1)register的幕后黑手
2016-03-17 16:32
411 查看
[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)
register(this)就是去当前类,遍历所有的方法,按照事件处理方法的命名规则约束(onEvent开头,只有一个参数,非static,非abstract的public方法)过滤出事件处理方法然后进行存储。然后循环遍历当前类的父类,做同样的处理。通过阅读源代码发现如果子类没有覆写父类的事件处理方法,那么父类的事件处理方法将会加入事件处理方法列表。
private synchronized void register(Object subscriber, boolean sticky, int priority) { /*getClass():* Returns the unique instance of Class that represents this object's class.*/ /*过滤出订阅者的所有事件处理方法(包括父类的),以列表形式返回*/ List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass()); for (SubscriberMethod subscriberMethod : subscriberMethods) { /*遍历,对订阅者的每一个事件处理方法进行保存/ subscribe(subscriber, subscriberMethod, sticky, priority); } }
/** * @param subscriberClass * @return */ /*订阅者 subscriberClass:注册EventBus的Activity或其他组件,EventBus.getDefault().register(this)中的this*/ /*方法findSubscriberMethods的作用是过滤出订阅者的所有事件处理方法方法,以列表形式返回*/ /*在EventBus中的观察者通常有四种订阅函数(就是某件事情发生被调用的方法) 1、onEvent 2、onEventMainThread 3、onEventBackground 4、onEventAsync 这四种订阅函数都是使用onEvent开头的,它们的功能稍有不同,在介绍不同之前先介绍两个概念: 告知观察者事件发生时通过EventBus.post函数实现,这个过程叫做事件的发布,观察者被告知事件发生叫做事件的接收,是通过下面的订阅函数实现的。 onEvent:如果使用onEvent作为订阅函数,那么该事件在哪个线程发布出来的,onEvent就会在哪个线程中运行,也就是说发布事件和接收事件线程在同一个线程。 使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。 onEventMainThread:如果使用onEventMainThread作为订阅函数,那么不论事件是在哪个线程中发布出来的,都会在主线程中调用事件处理方法,这个在Android中是非常有用的,因为在Android中只能在UI线程中更新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。 onEvnetBackground:如果使用onEventBackgrond作为订阅函数,那么如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。 onEventAsync:使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync.*/ List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { /*getName():Returns the name of the class represented by this Class 返回订阅者的类名,比如xxx.xxx.xxx.MainActivity*/ String key = subscriberClass.getName(); List<SubscriberMethod> subscriberMethods; /* private static final Map<String, List<SubscriberMethod>> methodCache = new HashMap<String, List<SubscriberMethod>>();*/ /*方法缓存就是一个静态最终的HashMap,key是订阅者的类名,value是订阅者事件处理方法的列表*/ /*先读缓存,看能否命中*/ synchronized (methodCache) { subscriberMethods = methodCache.get(key); } /*如果缓存命中,直接返回缓存中的事件处理方法列表*/ if (subscriberMethods != null) { return subscriberMethods; } /*缓存不命中,开始按照事件处理方法的命名规则进行过滤*/ subscriberMethods = new ArrayList<SubscriberMethod>(); Class<?> clazz = subscriberClass; /*eventTypesFound存放的是事件处理方法的过滤结果,key就是过滤出来的事件处理方法,value就是声明了这个事件处理方法的订阅者的Class*/ /*因为是循环处理订阅者的所有父类的,所以如果子类覆写了父类的事件处理方法,那么父类和子类的事件处理方法名称和参数完全一致 * 而事件处理方法名称和参数是作为eventTypeFound的key存储的,key必须唯一*/ HashMap<String, Class> eventTypesFound = new HashMap<String, Class>(); /*注意这个StringBuilder类是在循环外创建的,在循环内创建就太冲动了*/ StringBuilder methodKeyBuilder = new StringBuilder(); /*循环的最后一句话:clazz = clazz.getSuperclass(); 表示不仅要找当前类的事件处理方法,还要找所有父类的事件处理方法*/ while (clazz != null) { String name = clazz.getName(); /*如果类名是以java. javax. android. 为前缀,说明是系统类,不处理系统的类,直接结束循环,这是出于性能的考虑*/ if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { // Skip system classes, this just degrades performance break; } // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) /*从EventBus2.2版本开始要求事件处理方法必须是公开的方法*/ try { // This is faster than getMethods, especially when subscribers a fat classes like Activities /* getDeclaredMethods():返回所有方法,不仅仅是公开的,但不包括继承的方法 getMethods():返回所有公开方法,包括继承来的方法,如果订阅者是个比较复杂的类,那么getDeclaredMethods()速度要快于getMethods() getDeclaredMethods():Returns an array containing Method objects for all methods declared in the class represented by this Class. */ Method[] methods = clazz.getDeclaredMethods(); /*对订阅者的所有方法进行过滤,得到事件处理方法列表*/ filterSubscriberMethods(subscriberMethods, eventTypesFound, methodKeyBuilder, methods); } catch (Throwable th) { th.printStackTrace(); // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 Method[] methods = subscriberClass.getMethods(); subscriberMethods.clear(); eventTypesFound.clear(); filterSubscriberMethods(subscriberMethods, eventTypesFound, methodKeyBuilder, methods); break; } /*获取父类,对订阅者的父类进行同样的处理*/ clazz = clazz.getSuperclass(); } /*如果组件注册了EventBus,就成为了订阅者,订阅者不能没有事件处理方法,否则抛出异常*/ if (subscriberMethods.isEmpty()) { throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called " + ON_EVENT_METHOD_NAME); } else { /*过滤一次事件处理方法还是挺麻烦的,所以还是加入缓存吧*/ synchronized (methodCache) { methodCache.put(key, subscriberMethods); } return subscriberMethods; } } /**对订阅者的所有方法进行过滤,得到事件处理方法列表 * @param subscriberMethods 返回的事件处理方法列表 * @param eventTypesFound 过滤出的时间处理方法 * @param methodKeyBuilder * @param methods 所有方法 */ private void filterSubscriberMethods(List<SubscriberMethod> subscriberMethods, HashMap<String, Class> eventTypesFound, StringBuilder methodKeyBuilder, Method[] methods) { /*遍历每个方法,对每个方法进行处理,判断是否为事件处理方法*/ for (Method method : methods) { /*得到方法名*/ String methodName = method.getName(); /*private static final String ON_EVENT_METHOD_NAME = "onEvent";*/ /*如果方法名以onEvent开头就接着处理*/ if (methodName.startsWith(ON_EVENT_METHOD_NAME)) { /*获取该方法的修饰符*/ int modifiers = method.getModifiers(); /*获取声明了这个方法的类*/ /*getDeclaringClass():returns the class that declares this method.*/ Class<?> methodClass = method.getDeclaringClass(); /* private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;*/ /*如果是非abstract、static的public方法,接着处理*/ if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { /*获取该方法的参数类型列表*/ Class<?>[] parameterTypes = method.getParameterTypes(); /*事件处理方法约定只有一个参数*/ if (parameterTypes.length == 1) { /*根据方法名判断线程类型*/ ThreadMode threadMode = getThreadMode(methodClass, method, methodName); /*如果这个方法不是事件处理方法,跳出这次循环*/ if (threadMode == null) { continue; } /*获取参数类型,事件处理函数只有一个参数,所以取参数列表的第一项*/ Class<?> eventType = parameterTypes[0]; methodKeyBuilder.setLength(0); methodKeyBuilder.append(methodName); methodKeyBuilder.append('>').append(eventType.getName()); /*举个例子,如果事件处理函数为 onEvent(AutoRefreshMsg msg) * 那么methodKey就为onEvent>AutoRefreshMsg*/ String methodKey = methodKeyBuilder.toString(); /*HashMap<String, Class> eventTypesFound 是传入的参数*/ /*eventTypesFound 中key为onEvent>AutoRefreshMsg这种格式的字符串,value为声明了该事件处理方法的类*/ /* HashMap : public V put(K key, V value) * Maps the specified key to the specified value. * @param key the key. * @param value the value. * @return the value of any previous mapping with the specified key or * code null if there was no such mapping. * 如果HashMap之前没有这样的K V对,或者说是这样的K V对第一次添加到HashMap,就返回null */ /* methodClassOld表示之前是否已经存储过了定义了这个事件处理方法的类,如果没有,那么methodClassOld==null*/ /*注意HashMap的put方法的返回值,返回对应k之前存储的value或者null如果HashMap*/ /*注意对订阅者事件处理方法的过滤是先过滤当前订阅者,然后循环过滤当前订阅者的父类*/ /*所以如果子类覆写了父类的事件处理方法,那么肯定先处理子类 * 先把此事件处理方法和子类的类Class存储在eventTypesFound * 然后再下一次循环处理父类的时候,调用map的put方法,因为子类覆写了父类的事件处理方法 * 所以key值存在,put方法返回之前对用的value,也就是子类的Class*/ Class methodClassOld = eventTypesFound.put(methodKey, methodClass); /* public boolean isAssignableFrom(Class<?> c) isAssignableFrom:Can c be assigned to this class */ /* Class<?> methodClass = method.getDeclaringClass();*/ /*注意这里或运算的短路性质*/ /* instanceof 针对实例 isAssignableFrom针对class对象*/ /* new A() instanceof B 判断A对象是否是B类的子类或B类的实例*/ /* B.class.isAssignableFrom(A.class) A类是否可以赋值给B类,也就是判断B是不是A的父类*/ /*对已事件处理方法,子类和父类的都一样,所以只把最底层的订阅者的事件处理方法加入事件处理方法列表 * eventTypesFound需要存储事件处理方法和Class类名,在子类、父类、父类的父类中,事件处理方法名只有把一个(覆写) * Class名多个,规定只存储最继承层次最底层那个子类的Class作为value*/ /*如果子类没有覆写父类的事件处理方法,那么就把父类的事件处理方法加入事件处理方法列表*/ if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) { // Only add if not already found in a sub class /*子类中没找到才添加*/ /* List<SubscriberMethod> subscriberMethods 方法传进来的参数*/ subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType)); } else { /*HashMap<String, Class> eventTypesFound 是传入的参数*/ /*eventTypesFound 中key为onEvent>AutoRefreshMsg这种格式的字符串,value为声明了该事件处理方法的类*/ // Revert the put, old class is further down the class hierarchy /*注意是先处理子类后处理父类*/ eventTypesFound.put(methodKey, methodClassOld); } } } else if (!skipMethodVerificationForClasses.containsKey(methodClass)) { Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + methodClass + "." + methodName); } } } } /** * 根据方法名称判断线程类型 * @param clazz 订阅者 * @param method * @param methodName 以onEvent开头的非static、abstract的public方法 * @return */ private ThreadMode getThreadMode(Class<?> clazz, Method method, String methodName) { /*private static final String ON_EVENT_METHOD_NAME = "onEvent";*/ /*去掉方法名前边的不变量onEvent,留下后边的变量区分线程类型*/ String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length()); ThreadMode threadMode; /*四种线程模型*/ if (modifierString.length() == 0) { /*onEvent:回调函数和发起事件的函数会在同一个线程中执行*/ threadMode = ThreadMode.PostThread; } else if (modifierString.equals("MainThread")) { /*onEventMainThread:回调函数会在主线程中执行,这个在Android中非常有用,因为在Android中禁止在子线程中修改UI*/ threadMode = ThreadMode.MainThread; } else if (modifierString.equals("BackgroundThread")) { /*onEventBackgroundThread:如果在主线程发布事件,那么在子线程中处理该事件; 吐过在子线程发布事件,那么事件处理方法就在这个子线程执行。*/ threadMode = ThreadMode.BackgroundThread; } else if (modifierString.equals("Async")) { /*onEventBusAsync:不管在哪个线程发布事件,都会另起一个线程去处理事件。*/ threadMode = ThreadMode.Async; } else { /*private final Map<Class<?>, Class<?>> skipMethodVerificationForClasses;*/ /*判断是不是可以跳过订阅者方法校验,不跳过就派出异常,跳过就返回null*/ if (!skipMethodVerificationForClasses.containsKey(clazz)) { throw new EventBusException("Illegal onEvent method, check for typos: " + method); } else { threadMode = null; } } return threadMode; }
相关文章推荐
- 三分法——凸函数求极值问题
- iOS中的日期时间
- java微信支付开发中遇到的各种问题,微信官方的DEMO就是一个坑
- 【leetcode】第15题:3sum(medium)
- hbase 新版本 java api 遍历
- 字符串的组合
- 关于iOS多线程
- UNIX网络编程 poll函数
- 字符串的组合
- CUBRID学习笔记 33 net事务 cubrid教程示例
- Android之环境搭建下载路径
- 夺命雷公狗---DEDECMS----7dedecms目录结构
- 第三次作业(2)
- 什么是session ?它和cookie有什么区别和联系
- 78. Subsets
- 3357: [Usaco2004]等差数列|DP
- mysql ERROR 1045 (28000): Access denied for user解决方法 (转)
- android文件上传到服务器
- 第三次作业(1) Visual Studio程序安装过程和练习过程
- 【Java】数组属性的例子