由浅入深了解EventBus:(四)
事件注册
在EventBus3.0框架中订阅者对事件进行注册/订阅是通过EventBus类中的register方法来实现的,register的方法参数就是我们的订阅者的实例;
public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
findSubscriberMethods
在register方法中首先获取订阅者的实例的类型,然后通过subscriberMethodFinder类中的findSubscriberMethods方法来查找这个订阅者类型中的所有的消息事件的处理方法列表;获取到所有的消息处理方法后遍历进行订阅/注册;在subscribe方法的内部就是对EventBus类中的Map表进行赋值;
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } //是否忽略注解器生成的MyEventBusIndex类 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; } }
subscriberMethodFinder类中的findSubscriberMethods方法中首先是通过从缓存中获取相应的消息事件处理列表;由于EventBus框架采用的是反射机制来处理,性能上肯定没有直接去new对象的效率高,为了解决了这个造成的性能问题,EventBus框架采用编译期间进行对标注了“@Subscribe”注解的函数进行缓存;
在3.0版本中,EventBus
提供了一个EventBusAnnotationProcessor
注解处理器来在编译期通过读取@Subscribe()
注解并解析,处理其中所包含的信息,然后生成java
类来保存所有订阅者关于订阅的信息,这样就比在运行时使用反射来获得这些订阅者的信息速度要快;对于缓存这块以后单独一个章节会讲到,这里不在做深入的分析;
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findUsingReflectionInSingleClass(findState); findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }
在findUsingReflection 方法中查找SubscriberMethod集合时,使用了FindState来传递消息; 在subscriberMethodFinder类中维护着一个数组长度默认值为4的静态数组,这个数组存储的就是FindState,这边保证了FindState类可以复用,避免重复创造过的FindState对象;
static class FindState { final List<SubscriberMethod> subscriberMethods = new ArrayList<>(); final Map<Class, Object> anyMethodByEventType = new HashMap<>(); final Map<String, Class> subscriberClassByMethodKey = new HashMap<>(); final StringBuilder methodKeyBuilder = new StringBuilder(128); Class<?> subscriberClass; Class<?> clazz; boolean skipSuperClasses; SubscriberInfo subscriberInfo; void initForSubscriber(Class<?> subscriberClass) { this.subscriberClass = clazz = subscriberClass; skipSuperClasses = false; subscriberInfo = null; } }
在FindState类中维护着2个类型字段;subscriberClass类型是订阅者的类型,clazz类型在初始化的时候和subscriberClass类型是一样,当skipSuperClasses为false时,循环查找基类时,clazz类型会重新赋值为订阅者基类的类型;
当FindState类初始化构造完成后,EventBus3.0框架就开始循环查找订阅者以及基类中的监听事件处理函数;关于查找的具体实现就在findUsingReflectionInSingleClass方法中;
private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { methods = findState.clazz.getMethods(); findState.skipSuperClasses = true; } for (Method method : methods) { int modifiers = method.getModifiers(); 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)) { ThreadMode threadMode = subscribeAnnotation.threadMode(); findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { 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)) { String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } }
在方法的内部,首先通过反射中的getDeclaredMethods方法获取订阅者(或者是基类)中的所有方法;进而循环去校验方法是否是监听事件的处理函数;
从(modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0 可以看出,事件监听处理函数必须是public;事件监听处理函数中参数必须只有一个,这个从parameterTypes.length == 1就可以看出;最重要的是事件监听处理函数必须是“Subscribe”注解标注的;
当上述条件都满足的情况,EventBus3.0框架就认为这个函数就是事件监听处理函数,进而创建SubscriberMethod类,并将其添加到FindState类中的subscriberMethods 集合中;再此操作之前,FindState类会通过checkAdd方法来校验是否已经添加过此事件类型;
FindState类中的moveToSuperclass方法作用就是判断是否支持从父类查找,当FindState类中skipSuperClasses为true时,直接跳出循环,当skipSuperClasses为false时,将FindState类中calzz字段赋值为基类的类型,然后继续while循环查找,直到calzz类为系统的类型时,跳出循环;
当所有的循环查找结束后,执行getMethodsAndRelease方法,其实就是将 FindState类中的subscriberMethods字段返回,并且重置subscriberMethodFinder类中的FindState数组;
subscribe
当通过subscriberMethodFinder类获取到订阅者中所有的事件监听函数时,下一步就是方法的订阅;在subscribe方法中接收2个参数,一个是订阅者的实例,另外一个是订阅者中的监听事件处理函数的封装的SubscriberMethod类;
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class<?> eventType = subscriberMethod.eventType; Subscription newSubscription = new Subscription(subscriber, subscriberMethod); CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); } else { if (subscriptions.contains(newSubscription)) { throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } } int size = subscriptions.size(); for (int i = 0; i <= size; i++) { if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } } List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); if (subscriberMethod.sticky) { if (eventInheritance) { 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); } } }
subscribe方法的执行流程,收到就是通过SubscriberMethod中的eventType 获取事件类型,然后封装一个Subscription实例,我们知道EventBus类中维护这个一个key为事件类型,value为Subscription集合的
Map集合(subscriptionsByEventType),因此框架首先会从subscriptionsByEventType查找是否存在SubscriberMethod中事件类型,没有的话就创建一个CopyOnWriteArrayList<Subscription>subscriptions并添加到 subscriptionsByEventType集合中;
由于EventBus框架支持事件的排序,因此根据 subscriberMethod.priority 来进行排序添加;当EventBus框架接收到事件后,就会从subscriptionsByEventType取出所有支持事件类型的Subscription,并依此进行分发;
在框架进行subscribe时,还会将订阅者实例中所有支持的消息事件监听函数添加到EventBus类中的typesBySubscriber列表中,主要目的是当解除绑定时加快查找的效率;
EventBus框架是支持粘性事件的,EventBus 将最新的粘性事件保存在内存中,性事件可以被传递给订阅者或显示查询。因此,你不需要任何特殊逻辑去获取已有的数据。
当消息监听函数中的“Subscribe”注解中的sticky==true时,则这个监听函数就是个粘性事件的处理函数;在 EventBus框架中,在订阅者进行subscribe时就进行粘性事件的分发,由于粘性事件是存储在stickyEvents集合中,依此遍历去执行这个粘性事件;具体的事件分发方式是和普通的事件分发是一样的;
事件解绑
事件的解绑非常的简单,只需要调用EventBus框架的unregister方法就可以,在unregister方法内部,首先通过方法参数中的订阅者实例查找EventBus类中的typesBySubscriber列表,查找出所支持的所有支持的消息监听函数,然后在依此从subscriptionsByEventType列表中移除,最后从typesBySubscriber移除;
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()); } }