EventBus 3.2.0 源码阅读
名词定义
- 订阅者:某一个类,通过
register()
方法完成注册. - 订阅方法:某一个方法,通过
@Subscribe
注解,是订阅事件被处理,消费的地方. - 订阅事件类型:订阅方法的入参,是订阅方法希望接受的事件类型.
@Subscribe
@Subscribe
注解可以指定三个值,分别是ThreadMode
,指定订阅方法在什么线程下处理订阅事件,默认为POSTRING
;sticky
,指定接受的订阅事件是否是粘性事件,默认为false
;priority
,指定订阅方法的优先级,默认为0
.
ThreadMode
POSTING
(默认值)
订阅方法会在发布线程(Posting Thread
)下完成事件的处理,即在发布线程下直接执行.
由于发布线程直接执行订阅方法,是同步的过程.因此,后续的事件发布,需要等待当前订阅方法的处理完成,才能继续进行.而发布线程可能是 UI 线程,因此,声明为POSTRING
的订阅方法不应该处理耗时任务,否则,会影响 UI 线程其他事件的处理以及后续订阅方法接收到订阅事件的速度.MAIN
,MAIN_ORDERED
(Android Only)
订阅方法会在UI 线程下完成事件的处理.
对于MAIN
,如果发布线程是 UI 线程,则直接执行;否则,通过 Handler 处理.(类似runOnUiThread()
)
如果是MAIN_ORDERED
,则不管发布线程是否是 UI 线程,都通过 Handler 处理.
同样,不能处理耗时任务.BACKGROUND
订阅方法会在非 UI 线程下完成事件的处理.
如果发布线程不是 UI 线程,则直接执行;否则,创建线程执行(如果上一个任务还在执行,后面添加的任务会和上一个任务在同一个线程下执行).
同样,不能处理耗时任务,避免后续订阅方法接收订阅事件.
非 Android 下,不区分 UI 线程和非 UI 线程.统一为BACKGROUND
.ASYNC
订阅方法会在独立线程下完成事件的处理.即,不管发布线程是否是 UI 线程,都会创建新线程执行.
可执行耗时任务.
EventBus 源码解析
注册流程
注册流程主要完成订阅方法,订阅者以及订阅事件类型之间的映射关系,并处理粘性订阅事件.
-
使用者通过
register()
发起注册,在register()
中,首先通过SubscriberMethodFinder
获取该订阅者的所有订阅方法.public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
-
通过
subscribe()
添加订阅者,订阅方法与订阅事件类型之间的映射.如果当前的处理的订阅方法订阅的事件是粘性事件,则同时完成粘性事件的处理.// Must be called in synchronized block 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) { // 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); } } } 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, isMainThread()); } }
注销流程
注销流程主要通过注册流程中创建的映射关系,获取到订阅事件类型与订阅者之间的映射关系,从某一订阅事件类型下的所有订阅中取消待注销的订阅者的订阅.
-
使用者通过
unregister()
发起注销,在unregister()
中,首先通过typesBySubscriber
获取该订阅者的所有订阅事件类型./** Unregisters the given subscriber from all event classes. */ 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 { logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } }
-
从获取到的订阅事件类型中找到待注销订阅者的订阅方法,并删除
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */ 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--; } } } }
发布流程
发布流程主要工作是,根据每一个订阅方法的ThreadMode
,选择不同的,执行订阅方法的途径.
发布流程主要有两种类型的事件.对于粘性事件,需要将事件保存,供后续使用;对于普通事件,则不需要保存.
-
粘性事件,需要先将粘性事件保存下来.之后走普通事件的发布流程.
/** * Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky * event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}. */ 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); }
-
post()
方法主要完成一些条件的初始化,和解决循环发布的问题.
PostingThreadState.eventQueue
主要用来解决在发布线程下直接执行订阅方法,而该订阅方法也会发布订阅事件导致的循环嵌套问题.
PostingThreadState.isPosting
主要用来,在取消事件分发过程中,判断当前线程是否是发布线程.
PostingThreadState.isMainThread
主要用来判断订阅方法是否可以直接执行/** Posts the given event to the event bus. */ public void post(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); // ThreadLocal变量 List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event); if (!postingState.isPosting) { // 是否处于发布状态,主要用来区分取消事件的操作是否是在Posting线程下执行,以便取消事件传递时使用. postingState.isMainThread = isMainThread(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } try { while (!eventQueue.isEmpty()) { postSingleEvent(eventQueue.remove(0), postingState); } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } } private boolean isMainThread() { return mainThreadSupport == null || mainThreadSupport.isMainThread(); }
-
postSingleEvent()
主要完成订阅事件类型是否存在订阅者的判断.private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; 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) { logger.log(Level.FINE, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } } } /** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */ 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; } } /** Recurses through super interfaces. */ static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) { for (Class<?> interfaceClass : interfaces) { if (!eventTypes.contains(interfaceClass)) { // 去重 eventTypes.add(interfaceClass); addInterfaces(eventTypes, interfaceClass.getInterfaces()); } } }
-
postSingleEventForEventType()
主要按照优先级顺序,将订阅事件发布到各个订阅方法.
PostingThreadState.event
主要用来,在取消后续事件发布的过程中,判断取消的事件是否是正在发布的事件.
PostingThreadState.subscription
主要用来,在取消后续事件发布的过程中,判断发起取消事件发布的订阅方法是否是POSTRING
.
PostingThreadState.canceled
主要用来,退出循环,中断事件发布.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; 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; }
-
postToSubscription()
主要判断能否在当前线程先直接执行订阅方法.如果可以,则直接执行;否则,通过Poster
完成相应处理.private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { // 不需要跨线程的订阅,直接执行. switch (subscription.subscriberMethod.threadMode) { case POSTING: invokeSubscriber(subscription, event); break; case MAIN: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; case MAIN_ORDERED: if (mainThreadPoster != null) { mainThreadPoster.enqueue(subscription, event); } else { // temporary: technically not correct as poster not decoupled from subscriber invokeSubscriber(subscription, event); } break; case BACKGROUND: // 在非Android下,isMainThread==false,mainThreadPoster==null,所以,POSTING,MAIN,MAIN_ORDERED,BACKGROUND都是直接执行的 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); } } /** * Invokes the subscriber if the subscriptions is still active. Skipping subscriptions prevents race conditions * between {@link #unregister(Object)} and event delivery. Otherwise the event might be delivered after the * subscriber unregistered. This is particularly important for main thread delivery and registrations bound to the * live cycle of an Activity or Fragment. */ void invokeSubscriber(PendingPost pendingPost) { // Poster调用此方法 Object event = pendingPost.event; Subscription subscription = pendingPost.subscription; PendingPost.releasePendingPost(pendingPost); if (subscription.active) { invokeSubscriber(subscription, event); } } 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); } }
取消订阅
-
取消普通的订阅事件
事件能够取消需要满足的条件:
cancelEventDelivery()
应该在发布线程中执行.
订阅方法对订阅事件的处理存在同步(在发布线程下直接执行)和异步两种情况.对于异步处理,由于处于不同的线程,没办法干涉到其他事件的处理,因此,不能完成取消事件传递的操作.
因此,取消事件传递就需要判断当前的线程是否是发布线程!postingState.isPosting
.
(因为发布线程下直接执行订阅方法,发布线程一定处于发布状态;而订阅方法如果是通过异步执行的,那么他所在的线程一定不在发布状态.).- 取消的事件类型应该是当前正在发布的类型.
取消事件发布是通过中断postSingleEventForEventType()
中的事件发布循环实现的,而这个循环是针对当前正在发布的事件进行的,所以,无法中断其他的事件发布.即,其他事件的发布还未开始,不能中断. cancelEventDelivery()
应该在POSTING
的订阅方法中执行.
声明为POSTING
以外的ThreadMode
,总会有通过Poster
执行的时候,由于cancelEventDelivery()
在不符合条件时,会直接抛出异常,导致程序崩溃.所以,要求为POSTING
,避免崩溃.
这些条件的作用,主要是防止错误置位
postingState.canceled
,导致在post()
时抛出异常./** * Called from a subscriber's event handling method, further event delivery will be canceled. Subsequent * subscribers * won't receive the event. Events are usually canceled by higher priority subscribers (see * {@link Subscribe#priority()}). Canceling is restricted to event handling methods running in posting thread * {@link ThreadMode#POSTING}. */ public void cancelEventDelivery(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); if (!postingState.isPosting) { // 判断是否是在发布线程下,只有订阅方法在发布线程下执行的时候,才能取消事件发布 throw new EventBusException( "This method may only be called from inside event handling methods on the posting thread"); } else if (event == null) { throw new EventBusException("Event may not be null"); } else if (postingState.event != event) { // 判断取消的事件是否是正在发布的事件,只能取消当前正在发布的事件 throw new EventBusException("Only the currently handled event may be aborted"); } else if (postingState.subscription.subscriberMethod.threadMode != ThreadMode.POSTING) { // 判断订阅方法是否是POSTING,只有是POSTING的订阅方法,才能取消事件发布 throw new EventBusException(" event handlers may only abort the incoming event"); } postingState.canceled = true; }
-
取消粘性事件
/** * Remove and gets the recent sticky event for the given event type. * * @see #postSticky(Object) */ public <T> T removeStickyEvent(Class<T> eventType) { // 通过订阅事件类型去除粘性事件 synchronized (stickyEvents) { return eventType.cast(stickyEvents.remove(eventType)); } } /** * Removes the sticky event if it equals to the given event. * * @return true if the events matched and the sticky event was removed. */ public boolean removeStickyEvent(Object event) { // 移除指定粘性事件 synchronized (stickyEvents) { Class<?> eventType = event.getClass(); Object existingEvent = stickyEvents.get(eventType); if (event.equals(existingEvent)) { stickyEvents.remove(eventType); return true; } else { return false; } } } /** * Removes all sticky events. */ public void removeAllStickyEvents() { synchronized (stickyEvents) { stickyEvents.clear(); } }
SubscriberMethodFinder
-
首先,
SubscriberMethodFinder
通过METHOD_CACHE
尝试从缓存中获取数据.如果缓存命中,这表明该类已被解析过,则直接返回缓存值;否则,判断是否在初始化时指定设置ignoreGeneratedIndex=true
,如果有,则通过反射的方式获取订阅方法;否则,使用索引获取订阅方法.最后,将订阅方法写入缓存中,并返回给 EventBus.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; } }
-
方法的获取借助
FindState
类进行.SubscriberMethodFinder
使用一个大小为 4 的FindState
的缓存池.使用时,通过prepareFindState
方法,从池中获取一个FindState
.如果获取不到,则临时创建一个使用.
使用时,将要解析的类写入到FindState
,完成初始化.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(); } private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findUsingReflectionInSingleClass(findState); findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }
-
通过反射的方式获取订阅方法中,首先通过
getDeclaredMethods()
获取类中声明的方法(不包含继承的方法).如果过程中出现异常,则改为使用getMethods()
获取public
方法,包括继承自父类/父接口的方法.如果使用getDeclaredMethods()
获取,则递归完成其父类的订阅方法获取.订阅方法需要满足的条件:
- 非
abstract
,static
,bridge
,synthetic
- 是
public
- 使用
@Subscribe
注解 - 参数有且只有一个
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findUsingReflectionInSingleClass(findState); findState.moveToSuperclass(); } return getMethodsAndRelease(findState); } private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { // This is faster than getMethods, especially when subscribers are fat classes like Activities methods = findState.clazz.getDeclaredMethods(); // 不会获取父类的方法 } catch (Throwable th) { // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 try { methods = findState.clazz.getMethods(); } catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad... String msg = "Could not inspect methods of " + findState.clazz.getName(); if (ignoreGeneratedIndex) { msg += ". Please consider using EventBus annotation processor to avoid reflection."; } else { msg += ". Please make this class visible to EventBus annotation processor to avoid reflection."; } throw new EventBusException(msg, error); } findState.skipSuperClasses = true; // 通过getMethods()获取的方法已经包含了父类的方法,不需要再递归了. } for (Method method : methods) { int modifiers = method.getModifiers(); if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { // 非abstract,static,bridge,synthetic,是public Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1) { // 订阅的方法参数有且只能有一个 Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); if (subscribeAnnotation != null) { // 使用@Subscribe注解 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"); } } }
- 非
-
通过索引的方式,直接从索引中获取订阅的方法;如果索引不存在,则使用反射的方式获取.
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); } private SubscriberInfo getSubscriberInfo(FindState findState) { if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) { // 第一次 findState.subscriberInfo == null,此处是通过findState.subscriberInfo,在递归的过程中,来获取父类的 subscriberInfo 的逻辑 SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo(); if (findState.clazz == superclassInfo.getSubscriberClass()) { return superclassInfo; } } if (subscriberInfoIndexes != null) { // 此处是首次进入,获取注册类自身的 subscriberInfo的逻辑 for (SubscriberInfoIndex index : subscriberInfoIndexes) { SubscriberInfo info = index.getSubscriberInfo(findState.clazz); if (info != null) { return info; } } } return null; }
FindState
方法去重,判断订阅的方法是否存在重复的情况.
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)) { // 此处是将existing放入subscriberClassByMethodKey中,给method去判断的
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this); // 对同一事件类型的第三次及以后的出现,不再进行该if判断
}
return checkAddWithMethodSignature(method, eventType);
}
}
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)) { // 方法不相同或相同方法所在类(methodClass)是已添加方法所在类(methodClassOld)的子类
// 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;
}
}
void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
// Skip system classes, this degrades performance.
// Also we might avoid some ClassNotFoundException (see FAQ for background).
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") ||
clazzName.startsWith("android.") || clazzName.startsWith("androidx.")) {
clazz = null;
}
}
}
Poster
-
AsyncPoster
对应
ASYNC
,使用线程池执行.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); }
-
BackgroundPoster
对应
BACKGROUND
,使用线程池执行.与ASYNC
不同的是,BACKGROUND
中,后一个任务如果在前一个任务执行的过程中加入队列,则会由上一个任务所在线程继续执行.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) { // 使得BACKGROUND的订阅方法尽可能在同一线程中执行 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) { eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e); } } finally { executorRunning = false; } }
-
HandlerPoster
对应
MAIN
和MAIN_ORDERED
,Handler
执行.与BackgroundPoster
类似,HandlerPoster
在一次处理中会尽可能多的完成订阅事件的处理.但是,作为 UI 线程,需要处理其他的事情.因此,订阅事件的处理不能无限制的执行.因此,HandlerPoster
对订阅事件的连续处理时长,做了 10ms 的限制.当连续处理时间超过 10ms 时,则中断下一个事件的处理,在下一次 UI 线程空闲的时候继续处理.public 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) { // 超过10ms,则中断处理,在下一次空闲时,继续 if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message"); } rescheduled = true; return; } } } finally { handlerActive = rescheduled; } }
PendingPost
待处理的发布事件,作为Poster
处理事件发布时的数据载体
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节点
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);
}
}
}
PendingPostQueue
待处理的发布事件的队列,每个Poster
持有一个
synchronized void enqueue(PendingPost pendingPost) {
if (pendingPost == null) {
throw new NullPointerException("null cannot be enqueued");
}
if (tail != null) {
tail.next = pendingPost;
tail = pendingPost;
} else if (head == null) {
head = tail = pendingPost;
} else {
throw new IllegalStateException("Head present, but no tail");
}
notifyAll();
}
synchronized PendingPost poll() {
PendingPost pendingPost = head;
if (head != null) {
head = head.next;
if (head == null) {
tail = null;
}
}
return pendingPost;
}
synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
if (head == null) {
wait(maxMillisToWait);
}
return poll();
}
EventBusBuilder
对 EventBus 进行定制的一些参数.
logSubscriberExceptions(boolean)
默认为true
.
在通过反射执行订阅方法时,如果抛出InvocationTargetException
,logSubscriberExceptions
控制是否打印日志.logNoSubscriberMessages(boolean)
默认为true
.
控制在处理订阅事件分发时,如果某一个事件类型没有找到订阅者,是否打印日志.sendSubscriberExceptionEvent(boolean)
默认为true
.
在通过反射执行订阅方法时,如果抛出InvocationTargetException
,sendSubscriberExceptionEvent
控制是否发布SubscriberExceptionEvent
事件(如果logSubscriberExceptions
为true
,会多打印一些日志).sendNoSubscriberEvent(boolean)
默认为true
.
控制在处理订阅事件分发时,如果某一个事件类型没有找到订阅者,是否发布NoSubscriberEvent
(该事件是测试用的).throwSubscriberException(boolean)
默认为false
.
在通过反射执行订阅方法时,如果抛出InvocationTargetException
,throwSubscriberException
控制是否抛出EventBusException
.eventInheritance(boolean)
默认为true
.
控制订阅事件类型是否要考虑超类的情况(即订阅方法接受的事件类型是发布事件类型的超类).关闭提升可 20%或更多的性能.executorService(ExecutorService)
默认为newCachedThreadPool
.
是AsyncPoster
和BackgroundPoster
执行任务的线程池.skipMethodVerificationFor(Class<?>)
使用ArrayList
存储,默认为空.
为以onEvent
开头的方法进行方法名称验证,以避免输入错误;使用此方法,您可以从此检查中排除订户类别.还禁用对方法修饰符(公共,非静态或抽象)的检查.(代码中没有用到)ignoreGeneratedIndex(boolean)
默认为false
.
控制在SubscriberMethodFinder
查找订阅方法时,是否忽略索引,强制使用反射.strictMethodVerification(boolean)
默认为false
.
控制在SubscriberMethodFinder
查找订阅方法时,如果@Subscribe
注解的方法不符合条件,是否抛出EventBusException
.addIndex(SubscriberInfoIndex)
使用ArrayList
存储,默认为空.
添加通过EventBus annotation preprocessor
生成的索引.logger(Logger)
默认为android.util.Log
.
自定义日志程序.installDefaultEventBus()
让EventBus.getDefault()
返回的是使用当前 builder 创建的 EventBus(在使用 default EventBus 之前,必须且仅调用一次).
代码中,并没有对EventBusException
进行 catch.因此,抛出异常会导致应用崩溃.
其他的问题
-
如何判断是否是 Android?
在EventBusBuilder
的getMainThreadSupport()
方法中,会尝试获取MainThreadSupport
(UI 线程的Poster
就是由它创建的).该方法会查找是否有android.util.Log
这个类.如果有,在尝试通过Looper.getMainLooper()
获取MainLooper
,如果获取成功,则认为是 Android,并创建MainThreadSupport
.// EventBusBuilder MainThreadSupport getMainThreadSupport() { if (mainThreadSupport != null) { return mainThreadSupport; } else if (AndroidLogger.isAndroidLogAvailable()) { Object looperOrNull = getAndroidMainLooperOrNull(); return looperOrNull == null ? null : new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull); } else { return null; } } // AndroidLogger static { boolean android = false; try { android = Class.forName("android.util.Log") != null; } catch (ClassNotFoundException e) { // OK } ANDROID_LOG_AVAILABLE = android; } public static boolean isAndroidLogAvailable() { return ANDROID_LOG_AVAILABLE; }
-
如何判断是否是 UI 线程?
通过判断当前线程的Looper
是否是MainLooper
完成.// AndroidHandlerMainThreadSupport public AndroidHandlerMainThreadSupport(Looper looper) { // EventBusBuilder中初始化时,使用MainLooper初始化 this.looper = looper; } public boolean isMainThread() { return looper == Looper.myLooper(); // Return the Looper object associated with the current thread. Returns null if the calling thread is not associated with a Looper. }
-
有关在订阅方法中执行
post()
可能导致的问题/** Posts the given event to the event bus. */ public void post(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); // ThreadLocal变量 List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event); if (!postingState.isPosting) { // 是否处于发布状态,主要用来区分取消事件的操作是否是在Posting线程下执行,以便取消事件传递时使用. postingState.isMainThread = isMainThread(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } try { while (!eventQueue.isEmpty()) { postSingleEvent(eventQueue.remove(0), postingState); } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } }
当在发布线程中直接执行的订阅方法内,调用
post()
方法,由于是直接执行,当前线程处于发布状态,因此,订阅方法中调用的post()
方法并不会立刻发布,而是加入队列中,等到当前事件发布完成,才会发布.
当在非发布线程中执行的订阅方法内,调用post()
方法,由于处于不同线程,因此,当前线程是非发布状态,订阅方法中调用的post()
方法会立刻发布事件,这样一来,当前在非发布线程中处理的事件将会由于新事件的发布,而暂停,等到新发布的事件结束后,才会接着执行.