EventBus用法和源码解析
本文于
1701
天之前发表,文中内容可能已经过时。
[TOC]
参照版本:
EventBus 3.0以后
为什么选择EventBus
简化了 组件交流方式
对事件通信双方解耦
灵活指定线程(4种线程模式)
速度快,性能好
库比较小,不占内存
使用方便
使用指南
角色
Event :事件
Subscriber :事件订阅者
Publisher :事件发布者
五种线程模式
POSTING :默认,发布和订阅在同一个线程
MAIN :事件处理函数的线程在主线程(UI)线程。不能进行耗时
操作,订阅者需快速返回以免阻塞主线程
MAIN_ORDERED :事件处理函数的线程在主线程(UI)线程。不能进行耗时
操作,不会阻塞线程
BACKGROUND :处理函数在后台线程,不能进行UI操作。发布在主线程,订阅会开启一个新的后台线程。发布在后台线程,事件处理函数也在该后台线程
ASYNC :无论事件发布的线程是哪一个,都会重新开辟一个新的子线程运行,不能进行UI操作
MAIN和MAIN_ORDERED区别
在MAIN
模式下,如果事件发布者post事件也是在主线程的话,会阻塞post事件所在的线程,意思是连续post多个事件,如果接收事件方法执行完,才能post下一个事件
post(1) ——> onReceiveMsg(1) ——>post(2)——>onReceiveMsg(2)——>post(3)——>onReceiveMsg(3)
如果事件发布者post事件不在主线程,连续post多个事件,同事在主线程是接收事件是耗时操作的话,执行的流程是非阻塞的
post(1)——>post(2)——>psot(3)——>onReceiveMsg(3) 或 post(1)——>post(2)——>psot(3)——>onReceiveMsg(2)——>onReceiveMsg(3)
MAIN_ORDERED模式下,无论什么场景都是非阻塞的
事件类型 普通事件 :注册和反注册后,发送EventBus.post()事件,在需要接收的地方使用@Subscribe方法,方法必须是public
粘性事件 :注册和反注册后,发送EventBus.postSticky()黏性事件,在需要接收的地方使用@Subscribe方法,方法必须是public,添加sticky = true
普通事件是先订阅后发送,粘性事件支持先发送后订阅
优先级 说明:优先级高的订阅者优先接收到任务
threadMode参数相同
只有走到threadMode参数为POSTING的时候才会停止该事件的继续分发
,调用cancelEventDelivery(xx)
混淆 1 2 3 4 5 6 7 8 9 10 -keepattributes *Annotation* -keepclassmembers class ** { @org.greenrobot.eventbus.Subscribe <methods>; } -keep enum org.greenrobot.eventbus.ThreadMode { *; } # Only required if you use AsyncExecutor -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { <init>(java.lang.Throwable); }
索引 目的:
如何使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 android { defaultConfig { javaCompileOptions { annotationProcessorOptions { arguments = [ eventBusIndex : 'com.example.myapp.MyEventBusIndex' ] } } } } dependencies { implementation 'org.greenrobot:eventbus:3.1.1' annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1' }
在\app\build\generated\source\apt\debug\package\
下可查看生成的MyEventBusIndex文件
在Application中使用
1 2 3 4 5 6 7 8 public class MyApplication extends Application { @Override public void onCreate () { super .onCreate(); EventBus.builder().addIndex(new MyEventBusIndex ()).installDefaultEventBus(); } }
如果想在整个应用使用默认实例
1 2 3 EventBus.builder().addIndex(new MyEventBusIndex ()).installDefaultEventBus(); EventBus eventBus = EventBus.getDefault();
源码解析
注册流程
1 2 3 4 5 6 7 8 9 10 11 public static EventBus getDefault () { if (defaultInstance == null ) { synchronized (EventBus.class) { if (defaultInstance == null ) { defaultInstance = new EventBus (); } } } return defaultInstance; }
getDefault使用单例模式,保证整个app只有唯一实例。初次进入会进入无参构造中初始化
1 2 3 4 5 6 7 public EventBus () { this (DEFAULT_BUILDER); }
1 private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder ();
由此可以看出来DEFAULT_BUILDED是EventBusBuilder实例,具体的初始化在下面这个方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 EventBus(EventBusBuilder builder) { logger = builder.getLogger(); subscriptionsByEventType = new HashMap <>(); typesBySubscriber = new HashMap <>(); stickyEvents = new ConcurrentHashMap <>(); mainThreadSupport = builder.getMainThreadSupport(); mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this ) : null ; 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中获取,这是典型的建造者模式,查看EventBusBuilder类
1 2 3 4 public EventBus build () { return new EventBus (this ); }
查看EventBus类
1 2 3 public static EventBusBuilder builder () { return new EventBusBuilder (); }
所以用两种初始化的方法:
EventBus.builder().build();
EventBus.getDefault()
EventBusBuilder中配置如下
成员变量
logSubscriberExceptions
:是否打印订阅者异常信息,默认开启
logNoSubscriberMessages
:某个事件没有订阅者时,是否打印信息,默认开启
sendSubscriberExceptionEvent
:出现订阅者异常时,是否发送异常事件,默认开启
sendNoSubscriberEvent
:某个事件没有订阅者时,是否发送无订阅者的事件,默认开启
throwSubscriberException
:是否抛出订阅者异常信息,默认关闭
eventInheritance
:事件是否可以继承形式订阅,默认开启
ignoreGeneratedIndex
:忽略索引生成,默认关闭
strictMethodVerification
:是否开启方法严格验证,默认关闭
executorService
:线程池,默认是newCachedThreadPool,即没有核心线程、但最大线程数是Integer.MAX_VALUE的线程池
skipMethodVerificationForClasses
:跳过为订阅者类里面的方法进行校验,校验包括注解信息、修饰符是否是public且非static\final的,默认为空
subscriberInfoIndexes
:订阅者信息索引,由注解处理器生成
mainThreadSupport
:专为Android的主线程定制,持有主线程looper引用
方法调用
addIndex(SubscriberInfoIndex index)
:添加索引
eventInheritance(boolean eventInheritance)
:是否支持事件继承
executorService(java.util.concurrent.ExecutorService executorService)
:提供用于一部和后台时间传递的自定义线程池
ignoreGeneratedIndex(boolean ignoreGeneratedIndex)
:强制使用反射,即使有生成的索引(默认值:false)。
skipMethodVerificationFor(java.lang.Class<?> clazz)
:对以onEvent开头的方法进行方法名验证,以避免键入错误;使用此方法,可以从此检查中排除订阅服务器类。
logNoSubscriberMessages(boolean logNoSubscriberMessages)
:当调用事件处理函数异常时是否打印异常信息
logSubscriberExceptions(boolean logSubscriberExceptions)
:当没有订阅者订阅该事件时是否打印日志
sendNoSubscriberEvent(boolean sendNoSubscriberEvent)
:当调用事件处理函数异常时是否发送 SubscriberExceptionEvent 事件,若此开关打开,订阅者可通过
1 public void onEvent (SubscriberExceptionEvent event)
订阅该事件进行处理,默认为 true。
sendSubscriberExceptionEvent(boolean sendSubscriberExceptionEvent)
:当没有事件处理函数对事件处理时是否发送 NoSubscriberEvent 事件,若此开关打开,订阅者可通过
1 public void onEvent (NoSubscriberEvent event)
订阅该事件进行处理,默认为 true。
strictMethodVerification**(boolean strictMethodVerification)
:启用严格的方法验证(默认值:false)。
throwSubscriberException**(boolean throwSubscriberException)
:如果订阅服务器引发异常,则失败(默认值:false)。
1 EventBus.builder().throwSubscriberException(true ).installDefaultEventBus()
根据builder的默认配置统计得出:
当出现订阅者异常时,打印异常log
当事件没有订阅者时,打印没有订阅者log
当出现订阅者异常时,发送异常事件
当事件没有订阅者时,发送无订阅者事件
捕获异常信息,防止崩溃
事件可以继承
编译时生成索引
采用最大限制是Integer.MAX_VALUE的缓存线程池
为每个订阅者类都进行方法校验
当处于Android平台时,确保可以切换到主线程
自定义配置
1 2 3 EventBus.builder().logNoSubscriberMessages(false ) .logSubscriberExceptions(false ).eventInheritance(false )... .installDefaultEventBus();
1 2 3 EventBus.builder().logNoSubscriberMessages(false ) .logSubscriberExceptions(false ).eventInheritance(false )... .build();
1 2 3 4 5 6 7 8 9 10 public EventBus installDefaultEventBus () { synchronized (EventBus.class) { if (EventBus.defaultInstance != null ) { throw new EventBusException ("Default instance already exists." + " It may be only set once before it's used the first time to ensure consistent behavior." ); } EventBus.defaultInstance = build(); return EventBus.defaultInstance; } }
1 2 3 public EventBus build () { return new EventBus (this ); }
installDefaultEventBus调用的也是build()方法,但是该方法多了一个单例,确保其全局的唯一性,所以使用build方法时需要自己维护其唯一性
注册 1 EventBus.getDefault().register(this);
进入register方法
1 2 3 4 5 6 7 8 9 10 11 12 public void register (Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this ) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
SubscriberMethod是什么?
1 2 3 4 5 6 7 8 9 10 public class SubscriberMethod { final Method method; final ThreadMode threadMode; final Class<?> eventType; final int priority; final boolean sticky; String methodString; ... }
既然该事件是我们订阅方法的详细参数,那么他是从哪里来的,跟踪findSubscriberMethods
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 private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap <>();...... 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; } }
从缓存中根据订阅者的class对象获取对应的所有订阅方法,继续跟踪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 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); ..... }
1 2 3 4 5 6 7 8 9 10 final class Subscription { final Object subscriber; final SubscriberMethod subscriberMethod; volatile boolean active; ... }
Subscription为记录每个订阅方法和其对应的订阅者类,active在解注册的时候会被置为false,详看解注册
继续讲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 private void subscribe (Object subscriber, SubscriberMethod subscriberMethod) { ... 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); } } }
如果是粘性事件,进入checkPostStickyEventToSubscription()方法中:
1 2 3 4 5 6 7 private void checkPostStickyEventToSubscription (Subscription newSubscription, Object stickyEvent) { if (stickyEvent != null ) { postToSubscription(newSubscription, stickyEvent, isMainThread()); } }
跳转到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 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 { 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); } }
最终的enqueue()方法都是调用的invokeSubscriber方法
总结:通过注解初始化订阅方法后,在register后,在缓存中获取所有该订阅者的方法,循环遍历订阅,新建newSubscription方法,根据priority优先级将newSubscription方法放入subscriptions中,判断如果是粘性事件
,则执行其对应的订阅方法。
解注册 1 EventBus.getDefault().unregister(this);
进入unregister方法
1 2 3 4 5 6 7 8 9 10 11 12 13 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()); } }
进入unsubscribeByEventType():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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--; } } } }
总结:从typesBySubscriber获取订阅事件类型,根据订阅事件类型从subscriptionsByEventType获取订阅者信息,将subscription的active置为false,并移除该subscription
明显看出时regist的逆过程
typesBySubscriber :键是订阅者类,值是订阅事件类型的map
subscriptionsByEventType:键是订阅事件类型,值是订阅者信息
subscription:订阅信息,封装了订阅者类型和订阅方法,还有判断是否已经注册的active
发布普通事件 1 EventBus.getDefault().post(EventType type);
进入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 28 public void post (Object event) { PostingThreadState postingState = currentPostingThreadState.get(); List<Object> eventQueue = postingState.eventQueue; eventQueue.add(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()) { postSingleEvent(eventQueue.remove(0 ), postingState); } } finally { postingState.isPosting = false ; postingState.isMainThread = false ; } } }
详看PostingThreadState是什么?
1 2 3 4 5 6 7 8 final static class PostingThreadState { final List<Object> eventQueue = new ArrayList <>(); boolean isPosting; boolean isMainThread; Subscription subscription; Object event; boolean canceled; }
PostingThreadState中包含了eventQueue和其他的标志位
进入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 29 30 31 32 33 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)); } } }
进入lookupAllEventTypes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap <>();...... 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; } }
进入postSingleEventForEventType:
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 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 ; }
进入postToSubscription中,发送事件到订阅者,根据模式不同,不同处理
总结:事件可继承,获取事件所有超类,挨个发布信息,反之则发布信息,根据不同的模式,在不同线程中做处理。
发布粘性事件 1 EventBus.getDefault().postSticky(EventType type);
进入postSticky:
1 2 3 4 5 6 7 8 9 public void postSticky (Object event) { synchronized (stickyEvents) { stickyEvents.put(event.getClass(), event); } post(event); }
在postSticky中将粘性事件放置在stickyEvents中,执行post事件,所以是先发送事件,
总结:在register中普通事件只是注册,而粘性事件多了一个步骤就是走了post的类似方法,在注册时会触发发布事件,这样在注册后就直接发布了。这就是粘性事件的原理。详看register源码