这一篇我们来分析EventBus的register()与unregister()方法。
EventBus.java
public void register(Object subscriber) {
......
// 得到传入对象的类型,如MainActivity.class
Class<?> subscriberClass = subscriber.getClass();
// 注释2 根据方法名可知,寻找@Subscribe标记的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
// 注释3 遍历了上面的方法集合
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//注释4 这里其实是做了粘性事件的分发,这也是粘性事件能够先发送,再注册也能接受到的直接原因,后面详细分析。
subscribe(subscriber, subscriberMethod);
}
}
}
紧跟注释2,看他是怎么寻找Subscribe方法的:
SubscriberMethodFinder.java
//用来缓存Subscriber方法,使用的线程安全的ConcurrentHashMap
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//key:类类型,如MainActivity.classs
//value: Subscriber方法列表
//先去缓存里找,找到直接返回
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
// ignoreGeneratedIndex是在SubscriberMethodFinder的构造方法中被赋值的,向上溯源,它的值来自EventBusBuilder,默认为false。
if (ignoreGeneratedIndex) {
// 注释1@findSubscriberMethods 直接使用反射获取subscriber方法列表
subscriberMethods = findUsingReflection(subscriberClass);
} else {
// 注释2@findSubscriberMethods 在ADT生成的索引类MyEventBusIndex中的Map缓存中查找
subscriberMethods = findUsingInfo(subscriberClass);
}
// 一个都没找到的话抛出异常
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
// 将查找到的subscriber方法列表,添加到map缓存方便下次使用,需要注意的是这个map和MyEventBusIndex中map的区别,这个map缓存的是当前调用了register()方法的类里的subscriber方法,而MyEventBusIndex中的map缓存的是所有类中的subscriber方法。
METHOD_CACHE.put(subscriberClass, subscriberMethods);
// 返回method列表
return subscriberMethods;
}
}
接下来进入注释1@findSubscriberMethods处的方法:
SubscriberMethodFinder.java
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//注意这个方法,留一个印象
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
这里先留个印象暂不往下分析,在上面findSubscriberMethods方法中的else分支中有一种情况也会调用到findUsingReflectionInSingleClass()方法后面一起看。
ok,我们来到注释2@findSubscriberMethods处的方法:
SubscriberMethodFinder.java
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//注释1@findUsingInfo,可先看下面对FindState的分析
FindState findState = prepareFindState();
//注释2@findUsingInfo 给findState的属性初始化赋值
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) { //由上行代码可知,findState.clazz不为空,进入while循环
//注释3@findUsingInfo
findState.subscriberInfo = getSubscriberInfo(findState);
// 在此系列文章第一篇中提到的,使用ADT方式这里就不为空
if (findState.subscriberInfo != null) {
//得到subscriberClass类中的所有subscriber方法
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
//在下面分析checkAdd方法,判断是否符合存储条件
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
//添加到订阅方法列表
findState.subscriberMethods.add(subscriberMethod);
}
}
} else { //反射的方式查找subscriber方法,通过遍历的方式将所有@Subscribe注解标记的方法存储到findState.subscriberMethods中,逻辑与上面ADT方式大同小异,就不在深入分析了
findUsingReflectionInSingleClass(findState);
}
//在下面分析此方法
findState.moveToSuperclass();
}
//将收集到的订阅方法列表返回
return getMethodsAndRelease(findState);
}
这个方法中反复提到了一个数据结构FindState,它是SubscriberMethodFinder的一个内部类,主要用来存储在查找Subscriber方法过程中产生的一些临时对象。我们可以先看下它的结构:
static class FindState {
//subscriber方法列表
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
//存储EventType和Method对象的对应关系
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
//存储subscriber方法的方法名与方法签名(EventBus自定义规则)
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
//方法签名
final StringBuilder methodKeyBuilder = new StringBuilder(128);
//外部传入的,如MainActivity.class
Class<?> subscriberClass;
Class<?> clazz;
//是否跳过父类
boolean skipSuperClasses;
//是一个接口,它的实现类是SimpleSubscriberInfo,即MyEventBusIndex中的map存储的value 对象
SubscriberInfo subscriberInfo;
......
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.
//先检查同一个订阅者(如:MainActivity.class)之前是否有相同类型的Event的方法,没有的话,直接返回true,表示可以添加
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
//否则看之前存储的这个对象是不是一个Method对象
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);
}
}
//这个方法用来判断同一个订阅者(如:MainActivity.class)中,是不是已经存在和当前要注册的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);
// methodClassOld和methodClass存在继承关系,换句话说之前存入的同名同参方法由父类继承而来,则当前的method也可以添加
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;
}
}
void moveToSuperclass() {
//初始化时的参数,默认为false
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;
}
}
}
}
通过注释1@findUsingInfo处的方法得到了一个FindState对象:
SubscriberMethodFinder.java
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();
}
在SubscriberMethodFinder类中维护了一个FindState对象池,应该为了避免对象频繁的创建和销毁造成内存抖动。
注释2@findUsingInfo处对FindState对象进行初始化赋值:
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
继续往下看注释3@findUsingInfo:
SubscriberMethodFinder.java
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;
}
}
// 而subscriberInfoIndexes则是在EventBus的构造方法中创建SubscriberMethodFinder对象时传入的,在此系列文章第二片中有提到,可知 subscriberInfoIndexes不为空
if (subscriberInfoIndexes != null) {
//这里的index对象对应的就是MyEventBusIndex类
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
//将findState.clazz作为key,取出MyEventBusIndex中的map中存储的SubscriberInfo对象
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
到此收集注册订阅方法的流程已结束,我们回过头来看一下EventBus.register()方法在注册完订阅方法之后还进行了什么操作:
EventBus.java
public void register(Object subscriber) {
if (AndroidDependenciesDetector.isAndroidSDKAvailable() && !AndroidDependenciesDetector.areAndroidComponentsAvailable()) {
// Crash if the user (developer) has not imported the Android compatibility library.
throw new RuntimeException("It looks like you are using EventBus on Android, " +
"make sure to add the \"eventbus\" Android library to your dependencies.");
}
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//当前已分析到这里
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//遍历订阅方法,执行subscribe()方法
subscribe(subscriber, subscriberMethod);
}
}
}
继续往下看:
EventBus.java
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
//将订阅者对象(如:MainActivity对象)与 订阅方法封装成一个新的数据结构
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
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);
}
}
//按优先级插入到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<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
//如果当前方法订阅的是粘性事件
if (subscriberMethod.sticky) {
//默认为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>).
//若stickyEvents中存储的未消费的Event事件(比如跳转MainActivity之前,
//进行了postSticky()操作)与此方法接收的Event事件类型匹配,
//则在此执行一次事件分发,也就是post操作,这也是粘性事件实现的核心原理。
// 在此埋个坑,stickyEvents map集合中的数据是在什么时候填充的呢?
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);
}
}
}
到此register()的源码分析就结束了,下面来顺便看下unregister()的源码,有了register()的源码基础,大家也能猜个大概unregister()无非就是将订阅者(如:MainActivity对象)对应的map缓存中的数据移除调,我们来具体看下代码:
EventBus.java
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());
}
}
正如我们的猜想,这部分比较简单,就不做过多分析了。