前言 EventBus是一个Android事件发布/订阅框架,通过解耦发布者和订阅者简化Android事件传递,这里的事件可以理解为消息。事件传递既可以用于Android四大组件间通讯,也可以用于异步线程和主线程间通讯等。 传统的事件传递方式包括:Handler、BroadcastReceiver、Interface回调,相比之下EventBus的优点是代码简洁,使用简单,并将事件发布和 订阅充分解耦 。
基本使用 建议阅读:EventBus使用详解 &EventBus 中文文档 &EventBus使用详解
初始化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; } public static EventBusBuilder builder() { return new EventBusBuilder(); } public EventBus() { this(DEFAULT_BUILDER); } EventBus(EventBusBuilder builder) { subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; sendNoSubscriberEvent = builder.sendNoSubscriberEvent; throwSubscriberException = builder.throwSubscriberException; eventInheritance = builder.eventInheritance; executorService = builder.executorService; }
上面是 EventBus 初始化的三个步骤,直观上看用到单例模式和Builder模式 ,将构造参数给分离了出来,实际上还用到了策略模式 ,其中Builder中有些参数用于代码执行的策略,就说,你传的参数不一样,我执行的方式不一样,像 ignoreGeneratedIndex 作用就是让 EventBus 如何查找出订阅方法的策略。这些布尔类型的参数,在分析代码中可以逐步的了解到,先了解一些缓存对象,以更容易的了解源码:
subscriptionsByEventType : 内部是一个Map集合,可以根据 EventType 查找订阅事件。
typesBySubscriber : 根据我们的订阅对象找到 EventType,用于注册和注销。
事件投递者 : mainThreadPoster, backgroundPoster, asyncPoster 根据订阅注解 ThreadMode 去选择不同的投递者,不同投递者投递事件,接收函数会执行在不同的线程中。
subscriberMethodFinder :查找方法用的,内部维护了一个订阅方法的集合。
注册 1 2 3 4 5 6 7 8 9 public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
register(this)中中把订阅者传了进来,register(this)方法的执行主要分为两个步骤,第一个就是 findSubscriberMethods 找出一个 SubscriberMethod 的集合,然后就遍历 SubscriberMethod 将订阅者和订阅者事件处理注册到EventBus,首先看 findSubscriberMethods() 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { //缓存命中,直接返回 return subscriberMethods; } //是否忽略APT生成的索引带来的优化 if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass); } else { subscriberMethods = findUsingInfo(subscriberClass); } if (subscriberMethods.isEmpty()) { throw new EventBusException("Subscriber " + subscriberClass + " and its super classes have no public methods with the @Subscribe annotation"); } else { //存入缓存并返回 METHOD_CACHE.put(subscriberClass, subscriberMethods); return subscriberMethods; } }
首先从缓存中查找订阅者的订阅事件处理方法,如果找到了就立马返回。如果缓存中没有的话,则根据 ignoreGeneratedIndex选择如何查找订阅方法,最后,找到订阅方法后,放入缓存,以免下次继续查找。ignoreGeneratedIndex默认就是false(是由创建EventBus的时候传递进去的Builder决定的,这个参数的含义是是否忽略编译的时候生成的索引,直接用反射的方式去获取事件订阅者的事件处理方法 ),那我们会执行 findUsingInfo() 方法,先分析findUsingInfo() 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findState.subscriberInfo = getSubscriberInfo(findState); if (findState.subscriberInfo != null) { SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); } } } else { findUsingReflectionInSingleClass(findState); } // 会会会会继续查找父类的方法 findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }
findUsingInfo() 方法的第一步是准备 FindState,prepareFindState()方法的源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 private FindState prepareFindState() { synchronized (FIND_STATE_POOL) { for (int i = 0; i < POOL_SIZE; i++) { FindState state = FIND_STATE_POOL[i]; if (state != null) { FIND_STATE_POOL[i] = null; return state; } } } return new FindState(); }
就是从对象池中拿出一个 FindState对象进行复用(节省了内存),FindState 中维护的是我们对订阅方法查找结果的封装。其实,往后面,我们就知道作者这里设计的非常精妙。第二步,initForSubscriber()就是将我们的订阅者传给FindState对象。第三步做的就是不断从订阅者和订阅者的父类去查找订阅方法,第三步的while循环中存在一个if判断,这里牵扯到EventBus 3.0提供的一个优化措施(前面讲到的ignoreGeneratedIndex变量如果设置为true就会忽略这个优化),后续进行讲解,这里我们只需要知道在我们没有进行任何设置的时候,默认是会执行findUsingReflectionInSingleClass()方法的,我们一起看下 findUsingReflectionInSingleClass():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { // This is faster than getMethods, especially when subscribers are fat classes like Activities //getDeclaredMethods能拿到所有(不包括继承的方法) methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 methods = findState.clazz.getMethods(); findState.skipSuperClasses = true; } for (Method method : methods) { int modifiers = method.getModifiers(); // 事件处理方法必须为public,这里过滤掉所有非public方法 if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { Class<?>[] parameterTypes = method.getParameterTypes(); // 事件处理方法必须只有一个参数 if (parameterTypes.length == 1) { Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); if (subscribeAnnotation != null) { Class<?> eventType = parameterTypes[0]; if (findState.checkAdd(method, eventType)) { //只有在子类中没有找到,才会添加到subscriberMethods ThreadMode threadMode = subscribeAnnotation.threadMode(); findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { // 如果某个方法加了@Subscribe注解,并且不是1个参数,则抛出EventBusException异常 String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException("@Subscribe method " + methodName + "must have exactly 1 parameter but has " + parameterTypes.length); } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { // 如果某个方法加了@Subscribe注解,并且不是public修饰,则抛出EventBusException异常 String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } }
代码主要逻辑就是对订阅者方法的遍历,看有没有注解,有的话就解析注解,最后将找到的订阅方法的集合封装到FindState对象中的subscriberMethods集合中。在解析添加了注解的方法的时候,有两种情况下会抛出异常,一个是添加了注解的方法不是pulic方法,另一个是添加了注解的方法的参数不只有一个,另外最终异常,会不会抛出还受到strictMethodVerification参数的限制,这个参数也是在构造EventBus的时候,由Builder决定的。另外,并不是所有的方法都会被添加到subscriberMethods集合中,在添加前会进行过滤,这个过滤是通过**checkAdd()**方法完成的,过滤主要针对以下的两种情况:
对于同一个 Event,当前类对该对象使用了多个方法进行了多次订阅,那么如果该 Event 被发射的时候,当前类会如何调用这些方法?
对于同一个 Event,父类对该对象进行了一次订阅,子类重写该订阅方法,那么如果该 Event 被发射的时候,父类子类当中会如何处理这些方法?
看下**checkAdd()**方法的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 boolean checkAdd(Method method, Class<?> eventType) { // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required. // Usually a subscriber doesn't have methods listening to the same event type. Object existing = anyMethodByEventType.put(eventType, method); if (existing == null) { return true; } else { if (existing instanceof Method) { if (!checkAddWithMethodSignature((Method) existing, eventType)) { // Paranoia check throw new IllegalStateException(); } // Put any non-Method object to "consume" the existing Method anyMethodByEventType.put(eventType, this); } return checkAddWithMethodSignature(method, eventType); } }
可以看到 anyMethodByEventType 使用了 Event 的 Class作为键,这像是意味着一个类对于同一个 Event 只能订阅一次,事实上是不是这样,还得继续看看checkAddWithMethodSignature(),其源码简化如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) { methodKeyBuilder.setLength(0); methodKeyBuilder.append(method.getName()); methodKeyBuilder.append('>').append(eventType.getName()); String methodKey = methodKeyBuilder.toString(); Class<?> methodClass = method.getDeclaringClass(); Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass); if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) { // Only add if not already found in a sub class return true; } else { // Revert the put, old class is further down the class hierarchy subscriberClassByMethodKey.put(methodKey, methodClassOld); return false; } }
可以看到 subscriberClassByMethodKey 使用方法名 + ‘>’ + 事件类型作为键,这意味着对于同一个类来说,subscriberClassByMethodKey 肯定不会键重复(毕竟一个类中不能够方法名相同且方法参数、个数都相同),因此它最终会返回 true。这意味着一个类如果使用了多个方法对同一个 Event 对象进行注册,那么当该 Event 对象被发射出来的时候,所有的方法都将会得到回调。
但是当父类执行上述操作的时候,如果子类有「显示」实现父类的订阅方法,那么第一次执行checkAddWithMethodSignature的时候subscriberClassByMethodKey.put(methodKey, methodClass) 返回值为空,方法返回true,在第二次执行checkAddWithMethodSignature的时候subscriberClassByMethodKey.put(methodKey, methodClass) 返回值不为空,且为当前方法所在类的子类,所以这时候会走入 if 下分支并返回 false。这意味着当子类「显示」实现父类的订阅方法的时候,如果此时发射指定 Event 的话,父类的订阅方法将不会执行,而仅会执行子类的订阅方法。
总结来说:
如果当前类中,对同一个事件有多个订阅方法,那么这些方法都会执行,
如果子类与父类中同时存在了相同事件处理函数,则父类中的不会被添加到subscriberMethods。
我们解析完了之后,在看findUsingInfo方法的最后,返回了getMethodsAndRelease(FindState) *,将我们的 FindState传给了getMethodsAndRelease()方法,getMethodsAndRelease()方法的源码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 private List<SubscriberMethod> getMethodsAndRelease(FindState findState) { List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods); findState.recycle(); synchronized (FIND_STATE_POOL) { for (int i = 0; i < POOL_SIZE; i++) { if (FIND_STATE_POOL[i] == null) { FIND_STATE_POOL[i] = findState; break; } } } return subscriberMethods; }
在解析完了之后,将订阅方法赋给List集合,再回收FindState,继续接收解析,内存没有半点浪费。最后,我们返回的是一个订阅方法的集合。这样,我们通过反射解析注解,找到订阅方法的方式,我们已经分析完了。接下来再看看通过apt处理器来查找事件处理方法,我们知道apt处理,是针对源码的处理,是执行在编译过程中的。所以性能要比反射好的多,所以推荐大家使用这种方式 *。 如果我们配置使用了apt进行编译时处理那么findUsingInfo 中**getSubscriberInfo(findState)**返回值就不会空了,这个时候就会执行后续的操作,可以看出后续操作没有任何反射操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findState.subscriberInfo = getSubscriberInfo(findState); if (findState.subscriberInfo != null) { SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); } } } else { findUsingReflectionInSingleClass(findState); } findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }
**getSubscriberInfo(findState)**的源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private SubscriberInfo getSubscriberInfo(FindState findState) { //查找是否存在订阅对象,有就直接返回 if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) { SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo(); if (findState.clazz == superclassInfo.getSubscriberClass()) { return superclassInfo; } } //从我们传入的MyEventBusIndex中查找是否存在订阅消息,订阅消息就是订阅方法,包括父类的订阅方法 if (subscriberInfoIndexes != null) { for (SubscriberInfoIndex index : subscriberInfoIndexes) { SubscriberInfo info = index.getSubscriberInfo(findState.clazz); if (info != null) { return info; } } } return null; }
上面一段代码是针对缓存的,如果缓存中有就直接返回,底下,是从 subscriberInfoIndexes 中查找订阅信息的。subscriberInfoIndexes 是从构建EventBus的时候传递进去的EventBusBuilder对象中得到的:
1 2 3 4 5 6 7 8 9 10 11 12 13 private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool(); boolean logSubscriberExceptions = true; boolean logNoSubscriberMessages = true; boolean sendSubscriberExceptionEvent = true; boolean sendNoSubscriberEvent = true; boolean throwSubscriberException; boolean eventInheritance = true; boolean ignoreGeneratedIndex; boolean strictMethodVerification; ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; List<Class<?>> skipMethodVerificationForClasses; List<SubscriberInfoIndex> subscriberInfoIndexes;
EventBusBuilder中subscriberInfoIndexes默认是空的,我们需要对Buidler进行设置。具体操作如下,修改build文件:
1 2 3 4 5 6 7 8 9 10 //在defaultConfig中加入如下的代码 defaultConfig { javaCompileOptions{ annotationProcessorOptions{arguments=[eventBusIndex:'tk.thinkerzhangyan.myappli cation.MyEventBusIndex'] } } } //在dependencies中加入如下的代码 dependencies { annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.0.1' }
注意:Android Gradle插件2.2之前是使用apt的,2.2以后使用annotationProcessor代替了apt,建议阅读android-apt切换为官方annotationProcessor 。javaCompileOptions这里是生成加速配置文件,MyEventBusIndex就是生成文件的名字,前面就是你的包名,编译之后可以查看:
MyEventBusIndex.java的源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class MyEventBusIndex implements SubscriberInfoIndex { private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX; static { SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>(); putIndex(new SimpleSubscriberInfo(MainActivity.class, true, new SubscriberMethodInfo[] { new SubscriberMethodInfo("onDoEventOne", MainActivity.MyEvent.class), })); putIndex(new SimpleSubscriberInfo(Main2Activity.class, true, new SubscriberMethodInfo[] { new SubscriberMethodInfo("onDoEvent", MainActivity.MyEvent.class, ThreadMode.POSTING, 0, true), })); } private static void putIndex(SubscriberInfo info) { SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info); } @Override public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) { SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass); if (info != null) { return info; } else { return null; } } }
这个类中把我们的订阅类和订阅方法全找出来了,当我们这个类初始化的时候,我们的SUBSCRIBER_INDEX这个集合就已经有我们的订阅信息了,这样就不用在运行的时候再去通过反射获取了,提高了效率。最后一步,我们就通过EventBus初始化,将这个类给传进去:
1 EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus().register(this);
这样getSubscriberInfo方法就会返回SubscriberInfo对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findState.subscriberInfo = getSubscriberInfo(findState); if (findState.subscriberInfo != null) { SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); } } } else { findUsingReflectionInSingleClass(findState); } findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }
findUsingInfo方法中
1 2 3 4 5 6 SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); } }
代码就得到了执行,需要强调的是,我们是在编译过程中就已经找到我们的订阅信息了,不会在运行期做任何事情,所以这个效率是非常高的 。这样通过apt处理器来查找事件处理方法也分析完了,接下来再看看,当ignoreGeneratedIndex参数设置为true的时候,当这个参数设置为true的时候,会忽略apt优化设置,这时候会执行findUsingReflection(subscriberClass)去查找当订阅类的事件处理方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass); } else { subscriberMethods = findUsingInfo(subscriberClass); } if (subscriberMethods.isEmpty()) { throw new EventBusException("Subscriber " + subscriberClass + " and its super classes have no public methods with the @Subscribe annotation"); } else { METHOD_CACHE.put(subscriberClass, subscriberMethods); return subscriberMethods; } }
findUsingReflection(subscriberClass)方法的源码如下所示:
1 2 3 4 5 6 7 8 9 private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findUsingReflectionInSingleClass(findState); findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }
findUsingReflection(subscriberClass)方法和我们之前分析的findUsingReflectionInSingleClass(FindState findState)的逻辑基本是一样的,这里就不分析了。接下来继续分析register代码中的subscribe(subscriber, subscriberMethod)方法。
订阅 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 // Must be called in synchronized block private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class<?> eventType = subscriberMethod.eventType; Subscription newSubscription = new Subscription(subscriber, subscriberMethod); // 获取订阅了某种类型数据的Subscription。使用了CopyOnWriteArrayList,这个是线程//安全的,CopyOnWriteArrayList会在更新的时候,重新生成一份copy,其他线程使用的是copy,///不存在什么线程安全性的问题。 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); } else { if (subscriptions.contains(newSubscription)) { //如果已经被注册过了,则抛出EventBusException异常 throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } } int size = subscriptions.size(); for (int i = 0; i <= size; i++) { //根据优先级将newSubscription查到合适位置 if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } } //将处理事件类型添加到typesBySubscriber List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); // 如果该事件处理方法为粘性事件,即设置了“sticky=true”,则需要调用checkPostStickyEvent//ToSubscription判断是否有粘性事件需要处理,如果需要处理则触发一次事件处理函数 if (subscriberMethod.sticky) { if (eventInheritance) { // Existing sticky events of all subclasses of eventType have to be considered. // Note: Iterating over all events may be inefficient with lots of sticky events, // thus data structure should be changed to allow a more efficient lookup // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>). Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet(); for (Map.Entry<Class<?>, Object> entry : entries) { Class<?> candidateEventType = entry.getKey(); if (eventType.isAssignableFrom(candidateEventType)) { Object stickyEvent = entry.getValue(); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } } else { Object stickyEvent = stickyEvents.get(eventType); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } }
订阅的代码主要就做了两件事,第一件事情就是将我们的订阅方法和订阅者,封装到subscriptionsByEventType和typesBySubscriber。这两者的作用是什么?前者的作用,当我们投递订阅事件的时候,就会根据我们的 EventType从subscriptionsByEventType中找到我们的订阅事件,从而去分发事件,处理事件,具体的实现后面会讲到;后者的作用,是在调用unregister(this)的时候,根据订阅者从typesBySubscriber中找到我们的EventType,又根据我们的EventType从typesBySubscriber中找到找到订阅事件,从而解绑用的,解绑的代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 public synchronized void unregister(Object subscriber) { List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { for (Class<?> eventType : subscribedTypes) { unsubscribeByEventType(subscriber, eventType); } typesBySubscriber.remove(subscriber); } else { Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { int size = subscriptions.size(); for (int i = 0; i < size; i++) { Subscription subscription = subscriptions.get(i); if (subscription.subscriber == subscriber) { subscription.active = false; subscriptions.remove(i); i--; size--; } } } }
subscribe方法中做的第二件事,就是如果方法是处理粘性事件的话,就立马投递、执行相应的粘性事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 if (subscriberMethod.sticky) { if (eventInheritance) { // Existing sticky events of all subclasses of eventType have to be considered. // Note: Iterating over all events may be inefficient with lots of sticky events, // thus data structure should be changed to allow a more efficient lookup // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>). Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet(); for (Map.Entry<Class<?>, Object> entry : entries) { Class<?> candidateEventType = entry.getKey(); if (eventType.isAssignableFrom(candidateEventType)) { Object stickyEvent = entry.getValue(); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } } else { Object stickyEvent = stickyEvents.get(eventType); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } }
可以看到在执行处理粘性事件的方法的之前会根据eventInheritance进行判断,eventInheritance参数的含义是是否允许事件继承,这个参数也是由构建EventBus的时候,传递进去的Builder决定的,默认是true。当使用EventBus的时候如果我们的Event之间存在继承关系,可以将该字段设为 false 以提高性能 。如果设置为true,这个事件的所有子事件,都会被post。不管是否允许事件继承,都会执行checkPostStickyEventToSubscription(newSubscription, stickyEvent)方法,这个方法的源码如下所示:
1 2 3 4 5 6 7 private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) { if (stickyEvent != null) { // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state) // --> Strange corner case, which we don't take care of here. postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper()); } }
方法中调用了postToSubscription触发该事件的事件处理函数。postToSubscription函数后面讲post时会讲到。
发布 调用EventBus的post方法来发布事件,post方法的源码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 /** Posts the given event to the event bus. */ public void post(Object event) { //每个线程中都维护了一个投递的状态 PostingThreadState postingState = currentPostingThreadState.get(); List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event); // 确保不会被调用多次 if (!postingState.isPosting) { //标识post的线程是否是主线程 postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } try { //循环处理eventQueue中的每一个event对象 while (!eventQueue.isEmpty()) { postSingleEvent(eventQueue.remove(0), postingState); } } finally { //处理完之后重置postingState的一些标识信息 postingState.isPosting = false; postingState.isMainThread = false; } } }
currentPostingThreadState 是一个 ThreadLocal 类,通过它获取到 PostingThreadState 对象,再根据该对象获取到 event 链表(有没有联想到 Android 中的消息机制?),并将传入的 event 塞入该链表。PostingThreadState的定义:
1 2 3 4 5 6 7 8 9 10 /** For ThreadLocal, much faster to set (and get multiple values). */ final static class PostingThreadState { final List<Object> eventQueue = new ArrayList<Object>(); boolean isPosting; boolean isMainThread; Subscription subscription; Object event; boolean canceled; }
主要是有个成员eventQueue,由于是ThreadLocal,所以结果就是,每个线程有一个PostingThreadState对象,这个对象内部有一个事件的队列,并且有一个成员isPosting表示现在是否正在派发事件,当发送事件开始时,会依次取出队列中的事件发送出去,如果正在派发事件,那么post直接把事件加入队列后返回,还有个成员isMainThread,这个成员在实际派发事件时会用到,在postSingleEvent中会用到。 为了控制高并发下的一个 Event 回调不会被调用多次,利用PostingThreadState对象的isPosting 来标记当前链表是否已经开始进行回调操作,通过源码可以看到,每次分发完一个Event事件,该事件也会被从链表中remove出去,代码中调用了postSingleEvent方法来发布事件,postSingleEvent源码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; if (eventInheritance) { // 如果允许事件继承,则会调用lookupAllEventTypes查找所有的父类和接口类 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); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { //如果post的事件没有被注册,则post一个NoSubscriberEvent事件 post(new NoSubscriberEvent(this, event)); } } }
在postSingleEvent方法中,我们又见到了前面已经分析了的eventInheritance变量,这里先分析eventInheritance变量为false的情况,当eventInheritance变量为false的时候,会执行postSingleEventForEventType(event, postingState, eventClass)进行事件分发,这个方法的源码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { subscriptions = subscriptionsByEventType.get(eventClass); } if (subscriptions != null && !subscriptions.isEmpty()) { for (Subscription subscription : subscriptions) { postingState.event = event; postingState.subscription = subscription; boolean aborted = false; try { postToSubscription(subscription, event, postingState.isMainThread); aborted = postingState.canceled; } finally { postingState.event = null; postingState.subscription = null; postingState.canceled = false; } if (aborted) { break; } } return true; } return false; }
通过 subscriptionsByEventType获取该Event事件对应的订阅信息链表,然后将该订阅信息、Event 和当前线程信息传给了 postToSubscription()方法,该方法是用来回调所有订阅方法的,该方法的源码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { case POSTING: // 如果该事件处理函数没有指定线程模型或者线程模型为PostThread // 则调用invokeSubscriber在post的线程中执行事件处理函数 invokeSubscriber(subscription, event); break; case MAIN: // 如果该事件处理函数指定的线程模型为MainThread并且当前post的线程为主线程//,则调用invokeSubscriber在当前线程(主线程)中执行事件处理函数如果post的线程不是主线///程,将使用mainThreadPoster.enqueue该事件处理函数添加到主线程的消息队列中 if (isMainThread) { //当前是主线程,那就直接调用订阅函数 invokeSubscriber(subscription, event); } else { //当前是子线程,通过handler实现在主线程中执行 mainThreadPoster.enqueue(subscription, event); } break; case BACKGROUND: // 如果该事件处理函数指定的线程模型为BackgroundThread并且当前post的线程为主//线程,则调用backgroundPoster.enqueue如果post的线程不是主线程,则调用invokeSubscriber///在当前线程(非主线程)中执行事件处理函数 if (isMainThread) { //当前是主线程,创建一个runnable丢到线程池里面 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); } }
该方法主要是根据register注册的事件处理函数的线程模型在指定的线程中触发事件处理函数。关于EventBus的线程模型的概念,不明白的可以自己去查阅,这里就不讲解了。mainThreadPoster、backgroundPoster和asyncPoster分别是HandlerPoster、BackgroundPoster和AsyncPoster的对象,其中HandlerPoster继承自Handler,BackgroundPoster和AsyncPoster继承自Runnable。
接下来分析下这三个类,首先看下HandlerPoster,mainThreadPoster是在EventBus的构造函数中初始化的。
1 mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
在EventBus的构造函数中,我们看到mainThreadPoster初始化的时候,传入的是Looper.getMainLooper()。所以此Handle是运行在主线程中的。HandlerPoster的源码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 final class HandlerPoster extends Handler { private final PendingPostQueue queue; private final int maxMillisInsideHandleMessage; private final EventBus eventBus; private boolean handlerActive; HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) { super(looper); this.eventBus = eventBus; this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage; queue = new PendingPostQueue(); } void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); synchronized (this) { queue.enqueue(pendingPost); if (!handlerActive) { handlerActive = true; if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message"); } } } } @Override public void handleMessage(Message msg) { boolean rescheduled = false; try { long started = SystemClock.uptimeMillis(); while (true) { PendingPost pendingPost = queue.poll(); if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized pendingPost = queue.poll(); if (pendingPost == null) { handlerActive = false; return; } } } eventBus.invokeSubscriber(pendingPost); long timeInMethod = SystemClock.uptimeMillis() - started; if (timeInMethod >= maxMillisInsideHandleMessage) { if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message"); } rescheduled = true; return; } } } finally { handlerActive = rescheduled; } } }
HandlerPoster继承自Handler,有四个成员变量:
1 2 3 4 private final PendingPostQueue queue;//一个队列,用来存放PendingPost private final int maxMillisInsideHandleMessage;//handleMessage方法的执行的最长时间 private final EventBus eventBus;//当前的EventBus对象 private boolean handlerActive;//handleMessage方法是否在执行中
PendingPostQueue是一个队列,用来存放PendingPost,而PendingPost中维护的是事件Event和处理事件的Subscription,PendingPost源码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 final class PendingPost { private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>(); Object event; Subscription subscription; PendingPost next; private PendingPost(Object event, Subscription subscription) { this.event = event; this.subscription = subscription; } static PendingPost obtainPendingPost(Subscription subscription, Object event) { synchronized (pendingPostPool) { int size = pendingPostPool.size(); if (size > 0) { PendingPost pendingPost = pendingPostPool.remove(size - 1); pendingPost.event = event; pendingPost.subscription = subscription; pendingPost.next = null; return pendingPost; } } return new PendingPost(event, subscription); } static void releasePendingPost(PendingPost pendingPost) { pendingPost.event = null; pendingPost.subscription = null; pendingPost.next = null; synchronized (pendingPostPool) { // Don't let the pool grow indefinitely if (pendingPostPool.size() < 10000) { pendingPostPool.add(pendingPost); } } } }
PendingPost的构造方法是私有的,不能通过构造方法来创建PendingPost,PendingPost提供了obtainPendingPost和releasePendingPost来完成PendingPost的复用(没有的时候创建)和回收,这种实现使得内存得到了充分的利用。
当调用enqueue()方法时,会把这个事件加入队列中,如果当前没在派发消息就向自身发送Message触发handleMessage方法的执行。在handleMessage中会依次取出队列中的消息交由EventBus直接调用事件处理函数,而handleMessage执行所在的线程就是构造函数中传进来的Looper所属的线程,在EventBus中构造mainThreadPoster时传进来的是MainLooper,所以会在UI线程中执行。
解下来看下BackgroundPoster。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 final class BackgroundPoster implements Runnable { private final PendingPostQueue queue; private final EventBus eventBus; private volatile boolean executorRunning; BackgroundPoster(EventBus eventBus) { this.eventBus = eventBus; queue = new PendingPostQueue(); } public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); synchronized (this) { queue.enqueue(pendingPost); if (!executorRunning) { executorRunning = true; eventBus.getExecutorService().execute(this); } } } @Override public void run() { try { try { while (true) { PendingPost pendingPost = queue.poll(1000); if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized pendingPost = queue.poll(); if (pendingPost == null) { executorRunning = false; return; } } } eventBus.invokeSubscriber(pendingPost); } } catch (InterruptedException e) { Log.w("Event", Thread.currentThread().getName() + " was interruppted", e); } } finally { executorRunning = false; } } }
BackgroundPoster实现了Runnable接口,成员变量:
1 2 3 4 private final PendingPostQueue queue; private final EventBus eventBus; private volatile boolean executorRunning;
executorRunning用来标示run方法是否在执行中,通过这个变量,使得BackgroundPoster实现了单线程模式,当调用enqueue()方法时,会把这个事件加入队列中,如果executorRunning为false,说明BackgroundPoster没有在运行中,那么就会调用eventBus.getExecutorService()返回一个cache线程池来运行BackgroundPoster,如果executorRunning为true,说明BackgroundPoster在运行中,这个时候只会将事件加入到队列中,而不会开启新的线程去处理事件。当长时间无事件时BackgroundPoster所属的线程被会销毁,下次再Post事件时再创建新的线程。
我们可以看到run方法中会依次取出队列中的事件进行处理,由于所有的事件都是在一条线程中处理的,所以如果一个线程模式为BACKGROUND的事件处理方法中发生了阻塞,将会导致其他的事件处理方法得不到执行,我们要避免这种情况的发生 。
最后再来看下AsyncPoster:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class AsyncPoster implements Runnable { private final PendingPostQueue queue; private final EventBus eventBus; AsyncPoster(EventBus eventBus) { this.eventBus = eventBus; queue = new PendingPostQueue(); } public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); queue.enqueue(pendingPost); eventBus.getExecutorService().execute(this); } @Override public void run() { PendingPost pendingPost = queue.poll(); if(pendingPost == null) { throw new IllegalStateException("No pending post available"); } eventBus.invokeSubscriber(pendingPost); } }
AsyncPoster和BackgroundPoster是类似的,只不过每次调用他的enqueue()方法时候,除了会将事件插入到队列中外,都会开启一个新的线程来处理事件,所以不会出现一个方法阻塞,导致其他方法得不到执行的情况,这也是AsyncPoster和BackgroundPoster不同的地方。
这时候再回过头去看postToSubscription方法就没什么问题了,最后再看下invokeSubscriber(subscription, event)方法:
1 2 3 4 5 6 7 8 9 10 void invokeSubscriber(Subscription subscription, Object event) { try { //通过反射调用事件处理函数 subscription.subscriberMethod.method.invoke(subscription.subscriber, event); } catch (InvocationTargetException e) { handleSubscriberException(subscription, event, e.getCause()); } catch (IllegalAccessException e) { throw new IllegalStateException("Unexpected exception", e); } }
代码很简单,就是通过反射调用事件处理方法,来处理相应的事件,invokeSubscriber(pendingPost)是类似的。
1 2 3 4 5 6 7 8 void invokeSubscriber(PendingPost pendingPost) { Object event = pendingPost.event; Subscription subscription = pendingPost.subscription; PendingPost.releasePendingPost(pendingPost); if (subscription.active) { invokeSubscriber(subscription, event); } }
这样,当不允许事件继承的时候,调用post方法发送事件的流程,我们分析完了,接下来再看看允许事件继承的时候,调用post方法发送事件的流程,回到postSingleEvent方法,当允许事件继承的时候,以下的代码会得到执行:
1 2 3 4 5 6 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); }
当允许事件继承的时候,首先会调用lookupAllEventTypes方法来得到当前发送事件的所有父类事件类型,然后循环调用postSingleEventForEventType来发送事件(postSingleEventForEventTyp源码前面分析过了,这里就不再做分析了)这样,所有注册到EventBus的处理当前事件的父类事件的方法,都会被调用,用来处理当前的事件。看下lookupAllEventTypes(eventClass)的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) { synchronized (eventTypesCache) { List<Class<?>> eventTypes = eventTypesCache.get(eventClass); if (eventTypes == null) { eventTypes = new ArrayList<>(); Class<?> clazz = eventClass; while (clazz != null) { eventTypes.add(clazz); addInterfaces(eventTypes, clazz.getInterfaces()); clazz = clazz.getSuperclass(); } eventTypesCache.put(eventClass, eventTypes); } return eventTypes; } }
就是查找当前事件的所有父类型的事件,然后将当前事件的类型和所有父类事件的类型,都添加到eventTypesCache缓存起来,方便后续的使用。
到这里为止,通过post发布事件的整个流程代码就已经分析完了。
粘性事件 项目中如果想要发射 sticky 事件需要通过 EventBus#postSticky() 方式,源码如下:
1 2 3 4 5 6 7 public void postSticky(Object event) { synchronized (stickyEvents) { stickyEvents.put(event.getClass(), event); } // Should be posted after it is putted, in case the subscriber wants to remove immediately post(event); }
可以看到第一步是将该事件放入 stickyEvents 中,第二步则是正常 post()。为避免多线程操作 postSticky(Object) 和 removeStickyEvent(Class<?>) 引发的冲突,所以对 stickyEvents 对象添加了 synchronized关键字。前文在讲解EventBus#register()方法的时候已经对该方法中关于sticky事件的处理,进行过讲解,这里就不再叙述了。
EventBus中各个类的介绍 盗用的类图
EventBus
EventBus类负责所有对外暴露的API,其中的register()、post()、unregister()函数配合上自定义的EventType及事件响应函数即可完成核心功能。 EventBus默认可通过静态函数getDefault获取单例,当然有需要也可以通过’EventBusBuilder’或 构造函数新建一个EventBus,每个新建的EventBus发布和订阅事件都是相互隔离的,即一个EventBus对象中的发布者发布事件,另一个EventBus对象中的订阅者不会收到该订阅。
EventBusBuilder
跟一般Builder类似,用于在需要设置参数过多时构造EventBus。包含的属性也是EventBus的一些设置参数。build函数用于新建EventBus对象,installDefaultEventBus函数将当前设置应用于Default EventBus。
SubscriberMethodFinder
订阅者响应函数信息存储和查找类,上面具体分析过了,主要用于查找订阅者响应函数,如果不在缓存中,则遍历自己的每个函数并递归父类查找,查找成功后保存到缓存中。
SubscriberMethod
订阅者事件响应函数信息,包括响应方法、线程Mode、事件类型以及一个用来比较SubscriberMethod是否相等的特征值methodString,共四个变量。
Subscription
订阅者信息,包括subscriber对象、事件响应方法SubscriberMethod、优先级priority。
HandlerPoster
事件主线程处理,对应ThreadMode.MainThread。继承自Handler,enqueue函数将事件放到队列中,并利用handler发送message,handleMessage函数从队列中取事件,invoke事件响应函数处理。
AsyncPoster
事件异步线程处理,对应ThreadMode.Async,继承自Runnable。enqueue函数将事件放到队列中,并调用线程池执行当前任务,在run函数从队列中取事件,invoke事件响应函数处理。
BackgroundPoster
事件Background处理,对应ThreadMode.BackgroundThread,继承自Runnable。enqueue函数将事件放到队列中,并调用线程池执行当前任务,在run函数从队列中取事件,invoke事件响应函数处理。与AsyncPoster不同的是,BackgroundPoster中的任务只在同一个线程中依次执行,而不是并发执行。
PendingPost
订阅者和事件信息实体类,并含有同一队列中指向下一个对象的指针。通过缓存存储不用的对象,减少下次创建的性能消耗。
PendingPostQueue
通过head和tail指针维护一个PendingPost队列。HandlerPoster、AsyncPoster、BackgroundPoster都包含一个此队列实例,表示各自的订阅者及事件信息队列,在事件到来时进入队列,处理时从队列中取出一个元素进行处理。
SubscriberExceptionEvent
当调用事件处理函数异常时发送的EventBus内部自定义事件,通过post发送,订阅者可自行订阅这类事件进行处理。
NoSubscriberEvent
当没有事件处理函数对事件处理时发送的EventBus内部自定义事件,通过post发送,订阅者可自行订阅这类事件进行处理。
EventBusException
封装于’RuntimeException’之上的Exception,只是覆盖构造函数,相当于一个标记,标记是属于EventBus的Exception。
ThreadMode
线程模式枚举类,表示事件响应函数执行线程信息,包括ThreadMode.PostThread、ThreadMode.MainThread、ThreadMode.BackgroundThread、ThreadMode.Async四种。
总结 优化 eventInheritance
当使用EventBus的时候如果我们的Event之间存在继承关系,可以将该字段设为 false 以提高性能。
APT
EventBus 内部使用了大量的反射去寻找接收事件方法,实际上有经验的小伙伴知道可以使用 APT 来优化。这也就是EventBus 3.0引入的技术,代码中通过ignoreGeneratedIndex来判断是否使用生成的APT代码去优化寻找接收事件的过程,如果开启了的话,那么将会通过subscriberInfoIndexes来快速得到接收事件方法的相关信息。如果没有在项目中接入 EventBus 的APT,那么可以将ignoreGeneratedIndex设为 false 提高性能。
设计技巧 设计模式
利用了单例模式,Builder模式和策略模式。
反射方法
EventBus 在获取接收事件方法的信息中,通过getDeclaredMethods()来获取类中所有方法而并不是通过 getMethods(),由于前者只反射当前类的方法(不包括隐式继承的父类方法),所以前者的效率较后者更高些。
FindState
以下代码是 FindState 的获取:
1 2 3 4 5 6 7 8 9 10 11 12 private FindState prepareFindState() { synchronized (FIND_STATE_POOL) { for (int i = 0; i < POOL_SIZE; i++) { FindState state = FIND_STATE_POOL[i]; if (state != null) { FIND_STATE_POOL[i] = null; return state; } } } return new FindState(); }
以下代码是 FindState 的回收复用:
1 2 3 4 5 6 7 8 9 10 11 12 13 private List<SubscriberMethod> getMethodsAndRelease(FindState findState) { List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods); findState.recycle(); synchronized (FIND_STATE_POOL) { for (int i = 0; i < POOL_SIZE; i++) { if (FIND_STATE_POOL[i] == null) { FIND_STATE_POOL[i] = findState; break; } } } return subscriberMethods; }
可以看到,EventBus 使用 FindState 并不是简单的 new,由于 FindState 在注册流程中使用频繁且创建耗费资源,故创建 FindState 池复用 FindState 对象,与此相同的还有 PendingPost,它用于反射调用接收事件方法,具体不在此扩展。
版本区别 2.2以后添加的订阅事件处理方法必须是公共方法,2.2以前没有这个要求; 3.0以后订阅事件处理方法使用了注解,3.0以前没使用注解;
扩展,如何自定义Android注解库 创建一个Module,在这个Module里面自定义注解,然后创建一个Module,在这个Modlue里面自定义注解处理器放。
自定义注解处理器的时候,常用到两个库:auto-service和javapoet 。
auto-service使用很简单,只需要在定义的注解处理器上添加@AutoService(Processor.class)即可,示例如下:
1 2 3 4 @AutoService(Processor.class) public class MyProcessor extends AbstractProcessor { .... }
如果不使用auto-service,需要我们自己手动的在相应的目录下创建相关的文件。步骤如下: 1、在 processors 库的 main 目录下新建 resources 资源文件夹; 2、在 resources文件夹下建立 META-INF/services 目录文件夹; 3、在 META-INF/services 目录文件夹下创建 javax.annotation.processing.Processor 文件; 4、在 javax.annotation.processing.Processor 文件写入注解处理器的全称,包括包路径;
这个文件的作用,就是告诉jvm(或者是编译器)我们自己定义的注解处理器的位置。如果没有这个文件的话,我们的注解处理器是根本不会起作用的。
关于javapoet的使用,请查阅API。
前面我们提到,需要将自定义的注解和注解解析器放在两个不同的Module里面,之所以将注解和注解处理器放在两个不同的Module里面,主要是因为,只有在编译的时候需要这个注解处理器,而在打包APK的时候这个注解处理器是不需要打包进APK里面的,所以我们单独给注解处理器建了一个Module。
注解处理器只在编译处理期间需要用到,编译处理完后就没有实际作用了,而主项目添加了这个库会引入很多不必要的文件,为了处理这个问题我们需要引入个插件android-apt,它能很好地处理这个问题。
它有两个目的:
允许配置只在编译时作为注解处理器的依赖,而不添加到最后的APK或library
设置源路径,使注解处理器生成的代码能被Android Studio正确的引用
1 伴随着 Android Gradle 插件 2.2 版本的发布,android-apt 作者在官网发表声明证实了后续将不会继续维护 android-apt,并推荐大家使用 Android 官方插件提供的相同能力。也就是说,大约三年前推出的 android-apt 即将告别开发者,退出历史舞台,Android Gradle 插件提供了名为 annotationProcessor 的功能来完全代替 android-apt。
annotationProcessor的功能和android-apt的功能是一样的。这里我们只介绍annotationProcessor的使用。
在工程中使用我们自定义的注解,需要在工程中依赖包含我们自定义注解的Module,为了使用我们自定义的注解解析器处理我们自定义的注解,需要借助于annotationProcessor。这些都可以通过配置gradle文件来完成,附录使用eventbus的gradle文件。
1 2 3 4 5 dependencies { compile 'org.greenrobot:eventbus:3.0.0' annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.0.1' }
依赖自定义的注解库:
1 compile 'org.greenrobot:eventbus:3.0.0'
借助于annotationProcessor依赖,自定义的注解处理处理器:
1 annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.0.1'
Android 注解指南
自定义注解之编译时注解(RetentionPolicy.CLASS)(一) (建议先看这个系列)自定义注解之编译时注解(RetentionPolicy.CLASS)(二)——JavaPoet 自定义注解之编译时注解(RetentionPolicy.CLASS)(三)—— 常用接口介绍
android-apt切换为官方annotationProcessor
Android」Android开发你需要知道的注解(Annotation)
Android进阶之自定义注解 (建议看这个)如何自定义 Android 注解? Android,几分钟教你怎么应用自定义注解
参考链接:
源码地址:GitHub地址 GitHub地址-带中文注解(新) GitHub地址-带中文注解(旧)
如何使用(新版本):eventbus EventBus使用详解 EventBus使用详解 EventBus使用详解 EventBus 中文文档
如何使用(老版本):EventBus使用详解(一)——初步使用EventBus EventBus使用详解(二)——EventBus使用进阶
源码解析:EventBus 3.0源码解析 聊一聊 EventBus 源码和设计之禅 事件分发框架——EventBus浅析 EventBus源码解析 进击的巨人——EventBus源码解析 (老版本)
快速Android开发系列通信篇之EventBus EventBus - 1 核心概念:事件传递/EventBus的优点/传统handler通信的两种方式(更新中) Eventbus3代码分析(六):SubscriberMethodFinder类
相关Java知识:getMethods 与 getDeclaredMethods 的区别
上一篇:高效的加载Bitmap避免内存溢出
下一篇:ButterKnife源码剖析