概念
EventBus是一个面向于Android与Java的对事件订阅与发布的处理的一种机制。简单的说它就是一种事件处理机制,该项目已经开源。下面是一张图能够很全面的体现它的运行。

这里将EventBus的工作原理分为三步来说明
- EventBus的注册与订阅
- EventBus的事件发布
- EventBus的注销
EventBus的注册
既然是对工作原理进行总结,那么废话不多说,我们直接进入EventBus的代码进行分析
该文章的代码都是基于EventBus3.0.0
来进行分析说明
在使用EventBus开始之前都会调用它的注册代码
1
| EventBus.getDefault().register(this)
|
通过getDefault()方法来获取EventBus的实例
1 2 3 4 5 6 7 8 9 10
| public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
|
通过源码发现其实就是一个典型的singleton pattern(单例模式),保证实例的全局化,减少资源的开销。
进入EventBus的注册代码:
1 2 3 4 5 6 7 8 9 10
| public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); //获取该订阅对象中的所有订阅了的方法 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
|
在这里有一个subscriberMethodFinder
成员字段,通过调用它的findSubscriberMethods方法来获取订阅的方法数组。转到findSubscriberMethods方法中看下它的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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; } }
|
上面关键部分的注释已经写出来了。如果本地缓存中没有,则获取方式根据ignoreGeneratedIndex
分为两种。其中ignoreGeneratedIndex
默认为false。该字段的值在EventBus实例化的适合默认进行了设置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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; }
|
显而易见是通过builder模式来配置默认的参数值,所以如果需要改变这其中的参数值,可以通过builder来设置
1 2
| EventBus eventBus = EventBus.builder().ignoreGeneratedIndex(true).build(); eventBus.register(this);
|
索引机制
既然默认是false,那么就会调用findUsingInfo方法
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 List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { //实例化findState FindState findState = prepareFindState(); //初始化findState findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { //获取订阅者的相关信息并保存在findState中 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(); } //将获取的订阅方法重新添加到一个新的List集合中,并释放findState中的资源 return getMethodsAndRelease(findState); }
|
这里的关键地方是getSubscriberInfo方法,用来获取订阅者的相关信息。该方法的内部查找是使用index索引。如果该方法还是没有找到,则转向使用反射机制进行获取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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; } } if (subscriberInfoIndexes != null) { //遍历查找订阅者的相关信息 for (SubscriberInfoIndex index : subscriberInfoIndexes) { SubscriberInfo info = index.getSubscriberInfo(findState.clazz); if (info != null) { return info; } } } return null; }
|
这里的subscriberInfoIndexes
就是之前builder中对应的相同字段属性的值。该集合的值可以通过builder来动态添加
1 2 3
| EventBus eventBus = EventBus.builder() .addIndex(new MyEventBusAppIndex()) .addIndex(new MyEventBusLibIndex()).build();
|
到这里就是全部通过index获取订阅方法的实现。该方法只有在EventBus 3.x
以上版本才有,因为没有使用反射机制,所以相对来说该方法的速度自然会比通过反射机制来获取更快。
反射机制
反射机制获取的主要实现是在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 //获取注册对象中声明的所以方法 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(); //获取公有且非抽象或者静态的方法 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 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"); } } }
|
关键注释已给出,主要是通过反射原理来获取订阅方法的所需信息。同时保存下来以便后续的事件发布。下面是之前反射机制步骤开始的外部调用方法源码
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); }
|
主要逻辑跟使用索引方式类似,只是少了对索引方式的查找。
订阅
回到register方法中,订阅者的所以订阅方法已经获取完毕,下一步就开始进行订阅操作,本质是对这些方法进行管理保存。那么直接看subscribe方法
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 60 61
| private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { //订阅方法中所申明的参数class类型 Class<?> eventType = subscriberMethod.eventType; //对订阅者与订阅者的方法建立联系,进行封装管理 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); //通过EventType来查找关联的subscribetions集合 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); //保存新的eventType的subscriptions 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++) { //根据订阅方法的优先级插入到subscriptions中 if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } } //根据订阅者来查找所有的EventType List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } //根据订阅者保存所有的EventType subscribedEvents.add(eventType); //对具有sticky类型的订阅方法进行直接发布处理 if (subscriberMethod.sticky) { //验证eventType与stickyEvent间的继承关系,默认为true 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(); //判断eventType是否是candidateEventType的父类或者同一种类型 if (eventType.isAssignableFrom(candidateEventType)) { Object stickyEvent = entry.getValue(); //发布事件 checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } } else { Object stickyEvent = stickyEvents.get(eventType); //发布事件 checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } }
|
订阅的处理主要分为两种情况,其中一种是非sticky类型,根据eventType来保存subscriptions与根据subscribe来保存eventType;另一种是sticky类型,那么最终都是对事件进行直接发布。
EventBus的发布
EventBus的发布是调用post方法,指定发布的Event类型,只要订阅者持有该相关Event类型的方法就都能收到发布的事件。具体使用如下:
1 2 3
| EventBus.getDefault().post(new MyEvent()); //或者发布sticky类型的event EventBus.getDefault().postSticky(new MyEvent());
|
对于sticky类型的事件发布,本质上还是调用了post的方法,只是增加了对sticky event的同步保存
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); }
|
所以我们还是直接看post方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public void post(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event); //本地线程是否正在发布event if (!postingState.isPosting) { postingState.isMainThread = isMainThread(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } try { while (!eventQueue.isEmpty()) { //逐一发布单个event postSingleEvent(eventQueue.remove(0), postingState); } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } }
|
在发布中有一个currentPostingThreadState字段,它是一个ThreadLocal,保证当前线程中只有一个发布队列在进行中。把所以需要发布的event加入到正在进行中的队形中。对该队列中的event进行逐个取出发布。实现方法为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 26 27 28
| private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; //如果开启了event的继承机制 if (eventInheritance) { //查找所有的eventType,即包括它的父类与实现的接口 List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); int countTypes = eventTypes.size(); for (int h = 0; h < countTypes; h++) { Class<?> clazz = eventTypes.get(h); //只要其中一个eventType被找到相应的subscription,就为true subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); } } else { //标识该eventType是否有相应的subscription subscriptionFound = postSingleEventForEventType(event, postingState, eventClass); } //如果没有找到,则发布一个默认的event 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)); } } }
|
从上面的源码可以看出关键代码是postSingleEventForEventType方法,找到对应的subscriptions,即所以与该eventType相关的订阅者中的订阅方法。
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
| private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { //通过eventType来找到对应的subscriptions 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中找到对应eventType的subscriptions,然后转入到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 36 37 38 39 40 41 42 43
| 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: 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); } }
|
这里根据不同的threadMode进行不同的处理,分别为
- POSTING:当前线程
- MAIN:主线程
- MAIN_ORDERED:主线程排队分发
- BACKGROUND:后台线程
- ASYNC:异步线程池
不管是排队分发还是直接分发,最终都会调用invokeSubscriber方法
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); } }
|
最终的发布实现还是使用了反射的原理,通过反射来定义订阅的方法。到这里EventBus的发布过程就结束了。下面进入最后的EventBus的注销。
EventBus的注销
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public synchronized void unregister(Object subscriber) { //通过订阅者查找到所有的eventType List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { for (Class<?> eventType : subscribedTypes) { //注销所有的subscriptions unsubscribeByEventType(subscriber, eventType); } //删除注销的订阅者 typesBySubscriber.remove(subscriber); } else { logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } }
|
复杂的都已经分析完了,相对来说EventBus的注销就简单多了,无非删除对于的资源信息。在unregister中首先通过typesBySubscriber找到订阅者的所以eventType,然后调用unsubscribeByEventType方法来删除所有的subscriptions,最后将订阅者从typesBySubscriber中移除。那么最后再来看下unsubscribeByEventType方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { //通过eventType找到对应的subscriptions List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { int size = subscriptions.size(); //遍历所有的subscription for (int i = 0; i < size; i++) { Subscription subscription = subscriptions.get(i); if (subscription.subscriber == subscriber) { //设置subscription的状态为非活跃状态,保证正在事件分发时,该subscription不被分发 subscription.active = false; //删除 subscriptions.remove(i); i--; size--; } } } }
|
逻辑也很简单,更新subscriptionsByEventType中的数据,将注销的订阅者的相关信息移除。到这里EventBus的注销也分析完毕。
总结
EventBus的主要流程是:对需要订阅的类进行register,在register过程中根据ignoreGeneratedIndex字段来分别进行index索引或者反射机制获取订阅者中的所有方法信息,另外如果index索引方法没有获取到对于的方法信息,最后还是会通过反射机制保底获取;然后就是subscribe,将获取到的方法信息信息进行保存;进一步就是post,从保存的方法信息中进行匹配到对于的event方法,通过反射机制的invoke调用匹配的方法;最后对不需要的订阅者进行注销,释放资源。
关注
