上一篇:深扒 EventBus:getDefault
FindState
再看 EventBus.register 方法源码之前,我们先来了解 SubscriberMethodFinder 的一个静态内部类 FindState,从字面上理解是查找状态,那到底是什么东西的查找状态呢,让我们先简单过一遍源码
static class FindState {
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
void recycle() {
subscriberMethods.clear();
anyMethodByEventType.clear();
subscriberClassByMethodKey.clear();
methodKeyBuilder.setLength(0);
subscriberClass = null;
clazz = null;
skipSuperClasses = false;
subscriberInfo = null;
}
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);
}
}
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;
}
}
void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** Skip system classes, this just degrades performance. */
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
}
什么?看完很懵逼?这里我们可以简化一下
static class FindState {
// 订阅方法的集合
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
// 按事件类型划分的任何方法
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
// 按方法类型定义订阅者类
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
// 方法关键建造者
final StringBuilder methodKeyBuilder = new StringBuilder(128);
// 订阅的类
Class<?> subscriberClass;
// clazz = subscriberClass
Class<?> clazz;
// 跳过父类(默认为false)
boolean skipSuperClasses;
// 订阅信息
SubscriberInfo subscriberInfo;
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
// 回收
void recycle() {}
// 检查添加
boolean checkAdd(Method method, Class<?> eventType) {}
// 检查添加方法的签名
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {}
// 向上查找
void moveToSuperclass() {}
}
我们可以从类的简化中获取需要的信息,这个其实就是用于保存被订阅类中的信息
接下来让我再看 SubscriberMethodFinder.prepareFindState 方法
这个方法其实就是在复用 FindState 对象,如果缓存池里面没有,就直接 new FindState,这种方式其实是用了享元设计模式,这样做的好处是什么呢?因为享元设计模式中的最大一个特点就是对象复用,那么问题又来了,为什么要复用对象呢?因为使用 FindState 次数非常多,为了避免重复创建导致不必要的内存浪费,所以 EventBus 采用享元设计模式来解决这一问题
SubscriberMethod
刚刚看完了 FindState 类,再来了解一下 SubscriberMethod 这个类是做什么的,先简单过一遍源码
/** EventBus内部使用并生成订阅者索引 */
/** Used internally by EventBus and generated subscriber indexes. */
public class SubscriberMethod {
final Method method;
final ThreadMode threadMode;
final Class<?> eventType;
final int priority;
final boolean sticky;
/** Used for efficient comparison */
String methodString;
public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
this.method = method;
this.threadMode = threadMode;
this.eventType = eventType;
this.priority = priority;
this.sticky = sticky;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (other instanceof SubscriberMethod) {
checkMethodString();
SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
otherSubscriberMethod.checkMethodString();
// Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
return methodString.equals(otherSubscriberMethod.methodString);
} else {
return false;
}
}
private synchronized void checkMethodString() {
if (methodString == null) {
// Method.toString has more overhead, just take relevant parts of the method
StringBuilder builder = new StringBuilder(64);
builder.append(method.getDeclaringClass().getName());
builder.append('#').append(method.getName());
builder.append('(').append(eventType.getName());
methodString = builder.toString();
}
}
@Override
public int hashCode() {
return method.hashCode();
}
}
同样的套路,我们先把类简化一下
public class SubscriberMethod {
// 反射的方法
final Method method;
// 线程调度
final ThreadMode threadMode;
// 参数类型
final Class<?> eventType;
// 优先级
final int priority;
// 是否为粘性事件
final boolean sticky;
public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
this.method = method;
this.threadMode = threadMode;
this.eventType = eventType;
this.priority = priority;
this.sticky = sticky;
}
}
这下真相大白了,这个 SubscriberMethod 就是专门记录被 @Subscribe 注解方法的一些信息,而 FindState 是专门记录订阅到 EventBus 中对象的一些信息。简单点来说,SubscriberMethod 是记录方法信息,而 FindState 是专门记录类的信息
EventBus.register
首先我们来看看这个方法的源码
看不懂没关系,我们先看一下注释
Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
are no longer interested in receiving events.
Subscribers have event handling methods that must be annotated by {@link Subscribe}.
The {@link Subscribe} annotation also allows configuration like {@link ThreadMode} and priority.
注册给定的订阅服务器来接收事件。订阅者必须调用{@link #unregister(Object)}
不再对接收事件感兴趣。
订阅者拥有必须由{@link Subscribe}注释的事件处理方法。
{@link Subscribe}注释还允许像{@link ThreadMode}和priority这样的配置。
接下来看一下 findSubscriberMethods 方法做了什么操作
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
// 先判断一下这个 class 类型之前有没有实例注册过 EventBus
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
// 如果有的话就不要再遍历一次了,直接将之前遍历的结果返回回去,提升执行效率
return subscriberMethods;
}
// 这个字段正是 EventBusBuilder.ignoreGeneratedIndex 传过来的
// 这个 EventBus 是支持编译时注解生成的方法,类似于 Butterknife
// 这个字段一定要搞懂,不懂的一定要回去看我前面两篇文章
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 这个字段的出处
public class EventBusBuilder {
boolean ignoreGeneratedIndex;
/** 翻译:强制使用反射,即使生成了索引(默认值:false) **/
/** Forces the use of reflection even if there's a generated index (default: false). */
public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) {
this.ignoreGeneratedIndex = ignoreGeneratedIndex;
return this;
}
}
findUsingInfo
既然 ignoreGeneratedIndex 默认值为 false,那么让我们先看一下 findUsingInfo 方法的源码
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
// FindState 类,还有 prepareFindState 方法刚刚已经讲过了,这里不再赘述
FindState findState = prepareFindState();
// 重置 FindState 对象中的一些字段,恢复到默认状态
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);
}
让我们一层一层解析源码,到底代码的作用是什么
while (findState.clazz != null) {
......
findState.moveToSuperclass();
}
class SubscriberMethodFinder {
static class FindState {
Class<?> subscriberClass; // 是否跳过父类
Class<?> clazz;
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false; // 不跳过父类
}
void recycle() {
subscriberClass = null;
clazz = null;
}
// 让我们简单看一下这段代码
void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** 跳过系统类,这只会降低性能 **/
/** Skip system classes, this just degrades performance. */
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
}
}
这是一段经过精简的源码,我们稍微看一下就能看懂,这是在查找被订阅对象全部的超类(父类)的被订阅的方法,特别是 moveToSuperclass 方法已经告诉我们了,当超类是系统类的时候不会再往上查找了,我们可以回顾一下 Object 类,它的完整包名是 java.lang.Object,也就是说到了 Object 类后会直接跳出,不会被遍历,因为 Object 类中不可能有被 @Subscribe 注解的方法,Activity 和 Fragment 也是同理
再看下一段代码,getSubscriberInfo 方法是块硬骨头,需要一点一点啃
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 让我们重点看一下这段代码的源码
findState.subscriberInfo = getSubscriberInfo(findState);
......
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
private List<SubscriberInfoIndex> subscriberInfoIndexes;
// 看这个方法名就知道这个方法是干什么的了(获取订阅信息)
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) {
// 遍历所有的索引(这里的索引是指 MyEventBusIndex 类,前面的文章已经介绍过了)
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
// 关于 List<SubscriberInfoIndex> 字段的来源可以看这里,前面的文章已经讲过的了
/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();
putIndex(new SimpleSubscriberInfo(com.gatewang.ksl.ui.fragment.PersonFragment.class, true,
new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onLoginEvent", com.gatewang.ksl.event.LoginEvent.class, ThreadMode.MAIN),
new SubscriberMethodInfo("onLoginOutEvent", com.gatewang.ksl.event.LoginOutEvent.class, ThreadMode.MAIN),
}));
putIndex(new SimpleSubscriberInfo(com.gatewang.ksl.ui.activity.MainActivity.class, true,
new SubscriberMethodInfo[] {
new SubscriberMethodInfo("goBackHomeEvent", com.gatewang.ksl.event.GoBackHomeEvent.class, ThreadMode.MAIN),
}));
.........
}
private static void putIndex(SubscriberInfo info) {
SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
}
@Override
public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
if (info != null) {
return info;
} else {
return null;
}
}
}
看过这些代码相信你应该懂了,原来我们项目中使用 @Subscribe 注解地方的信息都在这里,那么为什么要保存在这里呢?好处在哪儿呢?,让我们再回顾一下刚刚讲过的 ignoreGeneratedIndex 这个字段
public class EventBusBuilder {
boolean ignoreGeneratedIndex;
/** 翻译:强制使用反射,即使生成了索引(默认值:false) **/
/** Forces the use of reflection even if there's a generated index (default: false). */
public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) {
this.ignoreGeneratedIndex = ignoreGeneratedIndex;
return this;
}
}
现在我们能明白了,为什么默认不用强制使用反射,因为用反射来获取类和方法的信息比较耗性能,EventBus 出了一个 APT 自动生成代码插件,将项目中带有 @Subscribe 注解的地方保存到 MyEventBusIndex 中,这样我们就不需要通过反射获取了,这样是可以极大的提升执行效率
看完了 getSubscriberInfo 方法的作用,接下来看看剩下的代码
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);
}
findState.subscriberInfo = getSubscriberInfo(findState);
// 查找 APT 生成的索引类有没有保存这个类的注解信息
if (findState.subscriberInfo != null) {
// 如果有的话
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
// 遍历被注解所有的方法
for (SubscriberMethod subscriberMethod : array) {
// 检查被注解方法有没有被添加到 FindState 对象中,有的话就不要重复添加了
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
// 如果没有的话,让我们重点看一下这段代码
findUsingReflectionInSingleClass(findState);
}
// find Using Reflection In Single Class 翻译: 查找在单个类中使用反射
private void findUsingReflectionInSingleClass(FindState findState) {
// 创建一个数组,用于存放被注解的方法信息
Method[] methods;
try {
// 这比getMethods更快,特别是当订阅者是像 activity 这样的胖类时
// 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();
/**
* 这个方法必须是 public 的,并且不能为
* private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC
* 抽象方法,静态方法,接口方法,合成方法
*/
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
// 获取这个方法的参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
// 这个方法的参数必须只能有一个
if (parameterTypes.length == 1) {
// 获取方法上面的注解,例如:@Subscribe(threadMode = ThreadMode.MAIN)
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
// 这个方法必须要有这个 @Subscribe 注解才会往下执行
if (subscribeAnnotation != null) {
// 获取方法参数上面的类型
Class<?> eventType = parameterTypes[0];
// 检查有没有被添加到 FindState 对象中,有的话就不要重复添加了
if (findState.checkAdd(method, eventType)) {
// 获取需要被调用的线程类型
ThreadMode threadMode = subscribeAnnotation.threadMode();
// 添加这个方法的注解信息到 FindState 对象中
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");
}
}
}
// 简单看一下 @Subscribe 这个注解类
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING; // 默认将该方法和消息发送方在同一个线程中执行
/**
* 如果为真,则传递最近的粘性事件(用
* {@link EventBus#postSticky(Object)}到此订阅服务器(如果事件可用)。
*
* If true, delivers the most recent sticky event (posted with
* {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
*/
boolean sticky() default false; // 默认不是粘性消息
/**
* 订阅者优先级,以影响事件交付的顺序。
* 在同一个交付线程内({@link ThreadMode}),优先级更高的订阅者将在之前接收事件
* 其他优先级较低的。默认优先级为0。注意:优先级不影响顺序
* 使用不同的{@link ThreadMode}的订阅者之间的传递!
*
* Subscriber priority to influence the order of event delivery.
* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
* delivery among subscribers with different {@link ThreadMode}s! */
int priority() default 0; // 默认优先级为 0
}
看完了这个 findUsingInfo 方法的源码,我们大致了解了这个方法的作用和流程,其实就是在找被注解的类和方法,大致有两种方式,一种是通过自动生成的索引类 MyEventBusIndex(由 APT 自动生成的)获取到被注解的方法,这种方式比较高效,另一种是直接通过反射直接获取方法,这种效率会比较低下,所以 EventBus 默认会采用第一种方式,如果没有找到 MyEventBusIndex 类,则使用反射的方式获取
findUsingReflection
看完了 findUsingInfo ,再看 findUsingReflection
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
你会发现 findUsingReflection 就是 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);
}
经过对比可以看出,findUsingReflection 没有用 getSubscriberInfo 方法查找索引类,而是直接通过反射获取所需要的信息
刚刚我们好像漏掉了一个方法 getMethodsAndRelease 没讲,这个方法在 findUsingReflection 和 findUsingInfo 的最后一行出现了,让我们来看一下它的源码
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
// 创建一个新的集合对象,将 findState.subscriberMethods 这个集合的数据添加到新创建的集合中
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
// 对 FindState 里面的对象进行回收
findState.recycle();
// 将使用过的 FindState 存放到缓存池中,方便下次复用
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
// 将这个新的集合返回回去
return subscriberMethods;
}
你是否似曾感觉好像有一段代码是和这个方法对应的,没错就是 prepareFindState 方法,前面已经讲过了
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();
}
Subscription
在这里加一段小插曲,介绍一下 Subscription 类的作用
final class Subscription {
// 被订阅的对象:EventBus.register(Object subscriber)
final Object subscriber;
// 被订阅的方法:@Subscribe
final SubscriberMethod subscriberMethod;
/**
* 调用{@link EventBus#unregister(Object)}时为false,该函数由排队的事件交付检查
* {@link EventBus#invokeSubscriber(PendingPost)}以防止竞争条件
*
* Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
* {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
*/
volatile boolean active;
Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
this.subscriber = subscriber;
this.subscriberMethod = subscriberMethod;
active = true;
}
@Override
public boolean equals(Object other) {
if (other instanceof Subscription) {
Subscription otherSubscription = (Subscription) other;
return subscriber == otherSubscription.subscriber
&& subscriberMethod.equals(otherSubscription.subscriberMethod);
} else {
return false;
}
}
@Override
public int hashCode() {
return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
}
}
从上面这些字段可以看出来,Subscription 其实就是包装了订阅对象和里面订阅的方法信息
subscribe
你以为 EventBus.register 的源码都看完了?其实就看了 findSubscriberMethods 中的两个方法而已,让我们继续往下看
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
// 让我们重点看一下这段代码
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
// 这里使用了同步锁,EventBus 对线程安全的问题处理得很好啊
synchronized (this) {
// 遍历刚刚由 findSubscriberMethods 返回的集合(存放被 @Subscribe 注解的方法信息)
for (SubscriberMethod subscriberMethod : subscriberMethods) {
// 接下来再重点看一下这个方法的源码
subscribe(subscriber, subscriberMethod);
}
}
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; // 根据事件的类型存放订阅事件集合
private final Map<Object, List<Class<?>>> typesBySubscriber; // 根据被订阅对象存放事件类型的集合
private final Map<Class<?>, Object> stickyEvents; // 粘性事件集合
// 必须在同步块中调用
// Must be called in synchronized block
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);
// 处理粘性事件
if (subscriberMethod.sticky) {
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);
}
}
}
EventBus.unregister
总算把 EventBus.register 看完了,接下来看一看 EventBus.unregister 的源码
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 {
// 这个对象没有被订阅过(EventBus.register)
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
// 遍历事件类型集合
for (Class<?> eventType : subscribedTypes) {
// 将这个被订阅对象和所注册的事件类型移除掉
unsubscribeByEventType(subscriber, eventType);
}
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--;
}
}
}
}
总结
EventBus 有两种方式获取这个对象的订阅信息,第一种是通过 Apt 自动生成的索引类,第二种是通过反射直接获取类中注解的方法,显然第一种比较高效,EventBus 优先以第一种方式去获取, 第一种获取不到再使用第二种,如果用反射还获取不到,就会直接抛出异常,告诉开发者这个对象里面没有被 @Subscribe 注解的方法,所以这个对象不能被订阅到 EventBus 中(EventBus.register)。
如果通过第一种或者第二种可以获取得到的话,会将这些订阅的信息分别放到两个集合中,一个集合是按照订阅对象存放的订阅信息,EventBus.unregister 的时候会从这个集合中移除相应的订阅信息;而另一个集合是按照事件类型存放的订阅信息,可想而知 EventBus.post 会从这个集合获取相应的订阅信息,然后反射执行这些订阅的方法。