1、EventBus方法注册
先从注册的对象中找到对应的方法
1)先从对外声明的方法找,如果发生异常,再找全部方法
找全部方法的时候会设置变量findState.skipSuperClasses = true; 这样就不用再次找父类的方法了
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
try {
methods = findState.clazz.getMethods();
2)方法必须是public修饰的,并且不能是抽象 静态的方法(可设置让其报出异常)
3)方法必须是Subscribe注解修饰,并且方法的参数必须是有且只有1个(可设置让其报出异常)
4)找完本类后,通常回去找对应的父类的方法,(java和android这样的父类不包括)
5)负责查找方法的类是FindState,这个用到了享元模式,方便对象的复用,每次用完会把对象的状态置为原值,并放入缓存池中
6)如果是粘性方法,会取出对应的粘性事件,发给注册的这个方法
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
try {
methods = findState.clazz.getMethods();
} catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad...
String msg = "Could not inspect methods of " + findState.clazz.getName();
if (ignoreGeneratedIndex) {
msg += ". Please consider using EventBus annotation processor to avoid reflection.";
} else {
msg += ". Please make this class visible to EventBus annotation processor to avoid reflection.";
}
throw new EventBusException(msg, error);
}
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");
}
}
}
二、发送事件
发送消息分为发送正常事件和发送粘性事件:
发送粘性事件和发送正常事件的区别在于,把粘性事件放到粘性集合中放一份,然后调用发送正常事件的方法
1、 public void post(Object event)
2、 public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
发送事件分为以下几步:
1、把发送的事件放入待发送的集合中
2、找到这个事件的所有父类和实现的接口(允许事件继承关系的话,可通过变量设置)
3、遍历第2步中找到的所有事件,根据事件找到对应的方法,进行执行
根据事件找方法的操作为从map集合中找,key为这个事件的类型,value为存放了所有监听这个事件的方法的集合
4、方法执行中,涉及到在哪个线程执行的问题
EvenBus中方法所在的线程分为五种:
1)POSTING 方法执行线程和发事件的线程在同一个线程,这样可能会引起阻塞,必须等一个方法执行完后,才能把事件传递个下一个方法
2)MAIN 方法在主线程执行,如果发送事件的线程也在主线程,也可能会造成阻塞,需要等方法执行完后,才会传递给下一个方法
3)MAIN_ORDERED 方法在主线程执行,不会对发送事件造成阻塞,会把监听该事件的方法放到handler的消息队列中执行
4)BACKGROUND 子线程中执行,如果发送事件的线程不是主线程,则直接会在这个线程中执行,这种情况同样可能会引起阻塞,必须等一个方法执行完后,才能把事件传递个下一个方法
5)ASYNC 子线程中执行,总是保持和发送事件的线程不在同一个线程,会通过线程池进行执行方法
三、取消注册事件
这一步比较简单,eventBus里面有一个map集合,key为对应的注册的对象类,value为list集合,里面保存着和这对象类有关的所有event事件类型。
1、根据这个对象找出所有的事件类型,
2、然后再根据事件类型从另一个集合中找出事件类型所对应的所有方法
3、遍历这些方法,移除掉属于这个对象类的方法
取消注册事件就算成功了
在注册时,会根据是否用到了注册索引类来进行注册,这个是在编译阶段就把对应的方法找到了,可以提高执行效率,以后再进行分析
网友评论