最近在看EventBus的源码,想看看它好在哪里,跟广播相比,如果只是在app内通知获取数据,那用eventBus要相对方便得多,但如果是跨进程,那还是用广播吧,而且EventBus一次post只能传一个类,除非这个onEvent没有其它重载的函数,不然会抛异常:
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType) ;
看了整个流程,第一个重要的类是:SubscriberMethodFinder,涉及到EventBus的订阅跟发布。
如果是系统类了就跳过获取,再把这个类以及它的父类相关的onEvent方法找到,加入到subscriberMethods里去。
List<SubscriberMethod>
findSubscriberMethods
(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods ;
synchronized ( methodCache ) {
subscriberMethods = methodCache .get(subscriberClass) ;
}
if (subscriberMethods != null ) {
return subscriberMethods ;
}
subscriberMethods = new ArrayList<SubscriberMethod>() ;
Class<?> clazz = subscriberClass ;
HashMap<String , Class> eventTypesFound = new HashMap<String , Class>() ;
StringBuilder methodKeyBuilder = new StringBuilder() ;
// 循环获取父类
while (clazz != null ) {
String name = clazz.getName() ;
if (name.startsWith( "java." ) || name.startsWith( "javax." ) || name.startsWith( "android." )) {
// Skip system classes, this just degrades performance
break;
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
try {
// This is faster than getMethods, especially when subscribers a fat classes like Activities
Method[] methods = clazz.getDeclaredMethods() ;
filterSubscriberMethods(subscriberMethods , eventTypesFound , methodKeyBuilder , methods) ;
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
Method[] methods = subscriberClass.getMethods() ;
subscriberMethods.clear() ;
eventTypesFound.clear() ;
filterSubscriberMethods(subscriberMethods , eventTypesFound , methodKeyBuilder , methods) ;
break;
}
clazz = clazz.getSuperclass() ;
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException( "Subscriber " + subscriberClass + " has no public methods called "
+ ON_EVENT_METHOD_NAME ) ;
} else {
synchronized ( methodCache ) {
methodCache .put(subscriberClass , subscriberMethods) ;
}
return subscriberMethods ;
}
List<SubscriberMethod> subscriberMethods ;
synchronized ( methodCache ) {
subscriberMethods = methodCache .get(subscriberClass) ;
}
if (subscriberMethods != null ) {
return subscriberMethods ;
}
subscriberMethods = new ArrayList<SubscriberMethod>() ;
Class<?> clazz = subscriberClass ;
HashMap<String , Class> eventTypesFound = new HashMap<String , Class>() ;
StringBuilder methodKeyBuilder = new StringBuilder() ;
// 循环获取父类
while (clazz != null ) {
String name = clazz.getName() ;
if (name.startsWith( "java." ) || name.startsWith( "javax." ) || name.startsWith( "android." )) {
// Skip system classes, this just degrades performance
break;
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
try {
// This is faster than getMethods, especially when subscribers a fat classes like Activities
Method[] methods = clazz.getDeclaredMethods() ;
filterSubscriberMethods(subscriberMethods , eventTypesFound , methodKeyBuilder , methods) ;
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
Method[] methods = subscriberClass.getMethods() ;
subscriberMethods.clear() ;
eventTypesFound.clear() ;
filterSubscriberMethods(subscriberMethods , eventTypesFound , methodKeyBuilder , methods) ;
break;
}
clazz = clazz.getSuperclass() ;
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException( "Subscriber " + subscriberClass + " has no public methods called "
+ ON_EVENT_METHOD_NAME ) ;
} else {
synchronized ( methodCache ) {
methodCache .put(subscriberClass , subscriberMethods) ;
}
return subscriberMethods ;
}
}
如果是以onEvent开头的,就继续看这个函数的名称,看是放在哪个线程,先分析filerSubscriberMethobs函数。
事件类型是由方法名+第一个参数类型组成,new 一个由方法名,线程,事件类型组成的订阅者放到这个与这个类相应的list里。
private void
filterSubscriberMethods
(List<SubscriberMethod> subscriberMethods
,
HashMap<String , Class> eventTypesFound , StringBuilder methodKeyBuilder ,
Method[] methods) {
for (Method method : methods) {
String methodName = method.getName() ;
if (methodName.startsWith( ON_EVENT_METHOD_NAME )) {
int modifiers = method.getModifiers() ;
Class<?> methodClass = method.getDeclaringClass() ;
if ((modifiers & Modifier. PUBLIC ) != 0 && (modifiers & MODIFIERS_IGNORE ) == 0 ) {
Class<?>[] parameterTypes = method.getParameterTypes() ;
if (parameterTypes. length == 1 ) {
ThreadMode threadMode = getThreadMode(methodClass , method , methodName) ;
if (threadMode == null ) {
continue;
}
// 第一个参数类型
Class<?> eventType = parameterTypes[ 0 ] ;
methodKeyBuilder.setLength( 0 ) ;
methodKeyBuilder.append(methodName) ;
methodKeyBuilder.append( '>' ).append(eventType.getName()) ;
String methodKey = methodKeyBuilder.toString() ;
Class methodClassOld = eventTypesFound.put(methodKey , methodClass) ;
// 如果子类重写了父类的 onEvent 方法,只放入子类的
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
subscriberMethods.add( new SubscriberMethod(method , threadMode , eventType)) ;
} else {
// Revert the put, old class is further down the class hierarchy
eventTypesFound.put(methodKey , methodClassOld) ;
}
}
} else if (! skipMethodVerificationForClasses .containsKey(methodClass)) {
Log.d(EventBus. TAG , "Skipping method (not public, static or abstract): " + methodClass + "."
+ methodName) ;
}
}
}
HashMap<String , Class> eventTypesFound , StringBuilder methodKeyBuilder ,
Method[] methods) {
for (Method method : methods) {
String methodName = method.getName() ;
if (methodName.startsWith( ON_EVENT_METHOD_NAME )) {
int modifiers = method.getModifiers() ;
Class<?> methodClass = method.getDeclaringClass() ;
if ((modifiers & Modifier. PUBLIC ) != 0 && (modifiers & MODIFIERS_IGNORE ) == 0 ) {
Class<?>[] parameterTypes = method.getParameterTypes() ;
if (parameterTypes. length == 1 ) {
ThreadMode threadMode = getThreadMode(methodClass , method , methodName) ;
if (threadMode == null ) {
continue;
}
// 第一个参数类型
Class<?> eventType = parameterTypes[ 0 ] ;
methodKeyBuilder.setLength( 0 ) ;
methodKeyBuilder.append(methodName) ;
methodKeyBuilder.append( '>' ).append(eventType.getName()) ;
String methodKey = methodKeyBuilder.toString() ;
Class methodClassOld = eventTypesFound.put(methodKey , methodClass) ;
// 如果子类重写了父类的 onEvent 方法,只放入子类的
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
subscriberMethods.add( new SubscriberMethod(method , threadMode , eventType)) ;
} else {
// Revert the put, old class is further down the class hierarchy
eventTypesFound.put(methodKey , methodClassOld) ;
}
}
} else if (! skipMethodVerificationForClasses .containsKey(methodClass)) {
Log.d(EventBus. TAG , "Skipping method (not public, static or abstract): " + methodClass + "."
+ methodName) ;
}
}
}
}
看看onEvent后是什么字段,比如:MainThread。
private
ThreadMode
getThreadMode
(Class<?> clazz
,
Method method
,
String methodName) {
String modifierString = methodName.substring( ON_EVENT_METHOD_NAME .length()) ;
ThreadMode threadMode ;
if (modifierString.length() == 0 ) {
threadMode = ThreadMode. PostThread ;
} else if (modifierString.equals( "MainThread" )) {
threadMode = ThreadMode. MainThread ;
} else if (modifierString.equals( "BackgroundThread" )) {
threadMode = ThreadMode. BackgroundThread ;
} else if (modifierString.equals( "Async" )) {
threadMode = ThreadMode. Async ;
} else {
if (! skipMethodVerificationForClasses .containsKey(clazz)) {
throw new EventBusException( "Illegal onEvent method, check for typos: " + method) ;
} else {
threadMode = null;
}
}
return threadMode ;
String modifierString = methodName.substring( ON_EVENT_METHOD_NAME .length()) ;
ThreadMode threadMode ;
if (modifierString.length() == 0 ) {
threadMode = ThreadMode. PostThread ;
} else if (modifierString.equals( "MainThread" )) {
threadMode = ThreadMode. MainThread ;
} else if (modifierString.equals( "BackgroundThread" )) {
threadMode = ThreadMode. BackgroundThread ;
} else if (modifierString.equals( "Async" )) {
threadMode = ThreadMode. Async ;
} else {
if (! skipMethodVerificationForClasses .containsKey(clazz)) {
throw new EventBusException( "Illegal onEvent method, check for typos: " + method) ;
} else {
threadMode = null;
}
}
return threadMode ;
}
从这个类可知,这个类是用来在调用EventBus.getDefault().register(this)的时候,获取当前这个类的订阅方法的,以方法+第一个参数类型来做为eventType来做为订阅类型,统一放到SubscribeMethod里。
接下来就可以讲订阅流程了。
首先是
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault () {
if ( defaultInstance == null ) {
synchronized (EventBus. class ) {
if ( defaultInstance == null ) {
defaultInstance = new EventBus() ;
}
}
}
return defaultInstance ;
public static EventBus getDefault () {
if ( defaultInstance == null ) {
synchronized (EventBus. class ) {
if ( defaultInstance == null ) {
defaultInstance = new EventBus() ;
}
}
}
return defaultInstance ;
}
通过单例来使用EventBus,EventBus有几个register函数,但都会统一调用下面这个函数。
private synchronized void
register
(Object subscriber
, boolean
sticky
, int
priority) {
// 获得与这个类相对应的订阅方法,放到 SubScriberMethod
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder .findSubscriberMethods(subscriber.getClass()) ;
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber , subscriberMethod , sticky , priority) ;
}
// 获得与这个类相对应的订阅方法,放到 SubScriberMethod
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder .findSubscriberMethods(subscriber.getClass()) ;
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber , subscriberMethod , sticky , priority) ;
}
}
从这个函数可知,会先获取到这个类的onEvnent的订阅方法,在对每个方法进行订阅。在对这个类的每个函数进行注册时,做了三件事,
第一件是在subscriptionsByEventType里放入这个eventType的订阅者:Subsctiption(由类类型,方法,优先级),并且按优先级排序。第二件事在typesByScubscriptions是放入类型对应该的所有订阅,最后还要用于解除注册。第三步是
判断sticky;如果为true,从stickyEvents中根据eventType去查找有没有stickyEvent,如果有则立即发布去执行。stickyEvent其实就是我们post时的参数
// Must be called in synchronized block
private void subscribe (Object subscriber , SubscriberMethod subscriberMethod , boolean sticky , int priority) {
Class<?> eventType = subscriberMethod. eventType ;
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType .get(eventType) ;
Subscription newSubscription = new Subscription(subscriber , subscriberMethod , priority) ;
// 放入一个同个类作为 eventType 也就是参数 0 的订阅列表
if (subscriptions == null ) {
subscriptions = new CopyOnWriteArrayList<Subscription>() ;
subscriptionsByEventType .put(eventType , subscriptions) ;
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException( "Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType) ;
}
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
// subscriberMethod.method.setAccessible(true);
int size = subscriptions.size() ;
// 按优先级插入
for ( int i = 0 ; i <= size ; i++) {
if (i == size || newSubscription. priority > subscriptions.get(i). priority ) {
subscriptions.add(i , newSubscription) ;
break;
}
}
// 存放一个类有多少个订阅方法
List<Class<?>> subscribedEvents = typesBySubscriber .get(subscriber) ;
if (subscribedEvents == null ) {
subscribedEvents = new ArrayList<Class<?>>() ;
typesBySubscriber .put(subscriber , subscribedEvents) ;
}
subscribedEvents.add(eventType) ;
if (sticky) {
// 是否支持继承,默认是支持
// 判断 sticky ;如果为 true ,从 stickyEvents 中根据 eventType 去查找有没有 stickyEvent ,如果有则立即发布去执行。 stickyEvent 其实就是我们 post 时的参数
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 subscribe (Object subscriber , SubscriberMethod subscriberMethod , boolean sticky , int priority) {
Class<?> eventType = subscriberMethod. eventType ;
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType .get(eventType) ;
Subscription newSubscription = new Subscription(subscriber , subscriberMethod , priority) ;
// 放入一个同个类作为 eventType 也就是参数 0 的订阅列表
if (subscriptions == null ) {
subscriptions = new CopyOnWriteArrayList<Subscription>() ;
subscriptionsByEventType .put(eventType , subscriptions) ;
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException( "Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType) ;
}
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
// subscriberMethod.method.setAccessible(true);
int size = subscriptions.size() ;
// 按优先级插入
for ( int i = 0 ; i <= size ; i++) {
if (i == size || newSubscription. priority > subscriptions.get(i). priority ) {
subscriptions.add(i , newSubscription) ;
break;
}
}
// 存放一个类有多少个订阅方法
List<Class<?>> subscribedEvents = typesBySubscriber .get(subscriber) ;
if (subscribedEvents == null ) {
subscribedEvents = new ArrayList<Class<?>>() ;
typesBySubscriber .put(subscriber , subscribedEvents) ;
}
subscribedEvents.add(eventType) ;
if (sticky) {
// 是否支持继承,默认是支持
// 判断 sticky ;如果为 true ,从 stickyEvents 中根据 eventType 去查找有没有 stickyEvent ,如果有则立即发布去执行。 stickyEvent 其实就是我们 post 时的参数
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) ;
}
}
}
接下来是解除注册:
找到这个类的所有订阅类型并移除这个订阅类。
/** 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 {
Log.w( TAG , "Subscriber to unregister was not registered before: " + subscriber.getClass()) ;
}
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()) ;
}
}
找到与这个订阅类型相关的订阅类,移除
/** 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-- ;
}
}
}
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-- ;
}
}
}
}