一,写在前面
EventBus的使用还是比较简单的,对于框架的使用,不仅仅是知其然,更要知其所以然,还可以学到框架里一些优秀的设计理念。本篇文章将从源码角度解析EventBus的注册流程,对框架的使用可参考文章EventBus的使用。
二,EventBus构造方法
在使用EventBus订阅事件时,一般会调用EventBus.getDefault()获取EventBus的实例,它返回一个系统默认的EventBus实例。
EventBus$getDefault()源码如下:
static volatile EventBus defaultInstance;
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
//三个Map集合存储了订阅类,事件类型,订阅方法相关的数据,后面的注册流程会用到
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadSupport = builder.getMainThreadSupport();
//三个重要的Poster,在发送事件的流程中会用到
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
//builder.subscriberInfoIndexes为null,indexCount为0
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
//参数分别为null, false, false
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
//true
logSubscriberExceptions = builder.logSubscriberExceptions;
//true
logNoSubscriberMessages = builder.logNoSubscriberMessages;
//true
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
//true
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
//false
throwSubscriberException = builder.throwSubscriberException;
//true
eventInheritance = builder.eventInheritance;
//线程池对象
executorService = builder.executorService;
}
1-12行:采用单例设计模式的双重检查,对开发者提供一个单例的EventBus对象;
18行:借助类EventBusBuilder构造EventBus的初始化数据,具体解释见上述代码片段;
三,register方法
查看EventBus$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);
}
}
}
2行:获取订阅类A的Class实例;
3行:遍历订阅类A及其超类中的订阅方法,subscriberMethodFinder是SubscriberMethodFinder类型的变量,初始化在EventBus的构造方法中完成;
查看SubscriberMethodFinder$findSubscriberMethods方法,源码如下:
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;
}
}
1行:METHOD_CACHE是一个Map集合,key是订阅类的Class实例,value是存储了SubscriberMethod对象的List集合。SubscriberMethod存储了订阅方法相关的一些数据,后面会讲到。
5行:由于第一次遍历该订阅类的订阅方法,subscriberMethods == null;
9行:由EventBus的构造方法可知,ignoreGeneratedIndex为false,执行else逻辑;
12行:findUsingInfo方法,用于遍历该订阅类中所有的订阅方法,并返回一个List集合,下面会具体分析;
15行:若订阅类及其超类中没有@Subscribe注解的方法,抛出异常给开发者;
19行:遍历完订阅方法后,将数据存储在METHOD_CACHE集合中。若再次遍历订阅方法,直接在缓存METHOD_CACHE中取出数据即可。
查看SubscriberMethodFinder$findUsingInfo方法,源码如下:
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);
}
2行:调用prepareFindState方法,里面维护了一个对象池FIND_STATE_POOL来获取FindState对象;
prepareFindState方法源码:
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
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();
}
1行:创建一个FindState的对象数组,作为对象池;
6行:如果对象池中存在FindState对象,则直接使用对象池中的FindState对象,见第9行;
8行:如果对象池中的对象已被使用,需要设置为null;
回到findUsingInfo方法,为方便查看,重新粘贴其代码如下:
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);
}
3行:初始化类FindState中数据;
4行:findState.clazz == subscriberClass,不为null,执行while循环;
5行:由FindState构造方法可知:subscriberInfo为null;由EventBus的构造方法可知:subscriberInfoIndexes为null(暂不考虑索引加速)。于是,getSubscriberInfo方法返回null,执行else逻辑;
14行:调用findUsingReflectionInSingleClass方法,遍历订阅方法,下面会具体分析;
16行:调用moveToSuperclass方法,遍历订阅类的超类的订阅方法;
moveToSuperclass方法源码如下(解释见代码注释,很重要):
void moveToSuperclass() {
//由构造方法可知:skipSuperClasses为false
if (skipSuperClasses) {
clazz = null;
} else {
//clazz重新赋值,设置为订阅类的超类
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** Skip system classes, this just degrades performance. */
//如果当前订阅类的超类是Java,Android提供的类,clazz = null
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
//返回null,findUsingInfo方法跳出while循环
clazz = null;
}
}
}
第18行:遍历完订阅类及其超类的订阅方法后,调用getMethodsAndRelease方法,将使用完的FindState对象添加进对象池FIND_STATE_POOL中重复利用。
值得一提的是,EventBus使用对象池来提供FindState对象,重复利用对象池中的对象,很好的节约了内存。
getMethodsAndRelease方法源码:
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
//创建一个新的List集合,用于存储subscriberMethods中数据
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
//清理使用过的FindState对象中的数据,见第18行
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
//将FindState对象添加进对象池中
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}
void recycle() {
subscriberMethods.clear();
anyMethodByEventType.clear();
subscriberClassByMethodKey.clear();
methodKeyBuilder.setLength(0);
subscriberClass = null;
clazz = null;
skipSuperClasses = false;
subscriberInfo = null;
}
下面重点关注findUsingReflectionInSingleClass方法,该方法完成订阅方法的遍历;
findUsingReflectionInSingleClass源码如下:
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 = 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");
}
}
}
5行:findState.clazz表示订阅类的Class实例,getDeclaredMethods方法获取该类中所有的方法,包括private,default,protected,public修饰的方法,但不包括继承的方法。
8行:抛出异常,则调用getMethods方法,获取自身以及继承的public方法;
9行:修改skipSuperClasses为true,则前面的moveToSuperclass方法执行if逻辑,findUsingInfo方法跳出循环。因为getMethods方法已经遍历所有的超类的方法,便不再重复遍历超类的订阅方法,所以跳出循环;
13行:如果方法由public修饰,且不由static,abstract修饰,If语句为true。否则抛出异常,执行第30行;
15行:如果方法只有一个参数;
17行:如果方法被@Subscribe注解修饰;
18行,获取事件类型的class实例;
19行,对订阅方法进行过滤,目的:如果子类和其超类中存在一样的订阅方法,只保留子类的。(后面会重点分析checkAdd方法)
20行,获取注解@Subscribe的threadMode属性的值;
21行,将方法,事件类型,注解的属性封装在SubscriberMethod类中,并添加进subscriberMethods集合中;
查看checkAdd方法源码:
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
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)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
1行:anyMethodByEventType是一个Map集合,key:事件类型的Class实例,value:Method对象;
6行:如果第一次遍历该事件类型的方法,existing为null,执行if逻辑,返回true。如果是第n(n>=2)次遍历该事件类型的方法,existing != null,执行else逻辑。(系统会遍历当前订阅类及其超类的订阅方法,checkAdd方法可能是在遍历超类,遍历超类就可能出现与子类一样的订阅方法,因此要处理这种情况)
需要注意,有两种情况会再次遍历到事件类型相同的方法,分别是:
- 事件类型相同,方法名不同(两个方法在同一个类中;或一个方法在子类,一个方法在超类中)
- 事件类型相同,方法名相同(两个方法分别在子类和超类中)
11行,调用checkAddWithMethodSignature方法,第一个参数:Map集合中上一个Method对象,即该事件类型对应的第一个订阅方法;第二个参数:事件类型的Class实例。
该方法的目的:在subscriberClassByMethodKey集合中,存储该事件类型对应的第一个订阅方法的相关数据,这样遍历该事件类型的其他订阅方法会同其进行比较,过滤掉超类中相同的订阅方法。
查看checkAddWithMethodSignature方法源码(解释见代码片段):
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
//methodKey表示该事件类型对应的第一个订阅方法的方法名,参数类型的拼接字符串;
String methodKey = methodKeyBuilder.toString();
//第一个订阅方法所在类的Class实例
Class<?> methodClass = method.getDeclaringClass();
//第一次添加key为methodKey的数据,methodClassOld == null
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// 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;
}
}
回到checkAdd方法
16行:前面第11行了谈到checkAddWithMethodSignature方法的目的,对于同一个订阅事件,只存储第一个订阅方法的相关数据。这里的this指的是FindState对象,会使得第10行的判断语句为false,将不再调用第11行的checkAddWithMethodSignature方法。
18行:从该事件类型对应的第n(n>=2)个订阅方法开始,将继续调用checkAddWithMethodSignature方法用于过滤不需要的订阅方法,第一个参数是当前订阅方法的Method对象,第二个参数是事件类型的Class实例。
重新查看checkAddWithMethodSignature方法源码:
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)) {
// 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;
}
}
6行:该事件类型对应的当前订阅方法的相关数据,由方法名和参数类型拼接的字符串;
7行:该事件类型对应的当前订阅方法所在类的Class实例;
8行:前面提到,有两种情况会再次遍历到事件类型相同的方法,分别是:
- 事件类型相同,方法名不同(两个方法在同一个类中;或一个方法在子类,一个方法在超类中)
- 事件类型相同,方法名相同(两个方法分别在子类和超类中)
如果是第1种情况,由于方法名不同,methodKey不同,methodClassOld == null;
如果是第2中情况,由于方法名相同,methodKey相同,methodClassOld返回上一个订阅方法所在类的Class实例;
9行:若是第一种情况,则执行第11行逻辑。若是第二种情况,由于methodClassOld是methodClass的子类,isAssignableFrom方法返回false,执行else逻辑;
14行,在subscriberClassByMethodKey集合中,移除超类中相同的订阅方法,重新保存子类中的订阅方法;
15行,唯一返回false的地方,目的就是过滤掉超类中相同的订阅方法,使checkAdd方法返回false。
小结:遍历订阅类及其超类的订阅方法,并过滤掉超类中重复的订阅方法。
回到register方法,查看源码:
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//subscriberMethod封装Method,EventType,三个注解的属性值
subscribe(subscriber, subscriberMethod);
}
}
}
3行:findSubscriberMethods方法已做详细分析,SubscriberMethod类封装了订阅方法,事件类型,注解相关的数据。
7行,调用subscribe方法,第一个参数是订阅类的实例,第二个参数是SubscriberMethod对象。
查看subscribe方法源码:
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//返回该subscriberMethod对象的事件类型
Class<?> eventType = subscriberMethod.eventType;
//提供一个Subscription封装:订阅类+SubscriberMethod
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
//key:事件类型 value:list集合,存储着Subscription(包含:订阅类+SubscriberMethod)
subscriptionsByEventType.put(eventType, subscriptions);
} else {
//第n次调用EventBus$register方法时,if条件里值为true(n>=2)
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
//按照subscriberMethod的priority由大到小的顺序,添加进List集合;
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<>();
//key:订阅类 value:list集合,存储着事件类型
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
//如果订阅方法上@Subscribe注解的sticky属性值为true
if (subscriberMethod.sticky) {
//由构造方法可知:eventInheritance为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>).
/*
key: postSticky中事件类型的class实例, value:事件类型的实例
stickyEvents:该Map集合数据的添加,交由EventBus$postSticky方法完成
*/
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
//postSticky方法中的事件类型
Class<?> candidateEventType = entry.getKey();
//如果postSticky方法中的事件类型,是订阅方法中的事件类型的子类或者是一个类
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
/*
第一个参数:封装了订阅方法相关的信息
第二个参数:postSticky方法中的事件类型的实例
*/
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
调用subscribe方法在三个Map集合中存储,或取出订阅方法相关的数据,代码片段已做相关解释。
当多次注册同一个订阅类时,执行第22行抛出异常。
当粘性事件被接受,执行第73行的checkPostStickyEventToSubscription方法回调订阅方法,由于不是本篇文章的重点,具体细节会在EventBus的发送事件流程中介绍,敬请关注~
四,小结
EventBus的注册流程包括如下内容:
- 遍历订阅类及其超类的订阅方法,并过滤掉超类中重复的订阅方法,将数据存储在subscriberMethods集合中
- 将订阅方法相关的信息存储在subscriptionsByEventType,typesBySubscriber集合中
- 配合postSticky发送的粘性事件,回调订阅方法(先发送粘性事件,后注册订阅类)