EventBus3.0源码解析——03. register 注册
Posted 夜辉疾风
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EventBus3.0源码解析——03. register 注册相关的知识,希望对你有一定的参考价值。
register(注册)
//注册事件接收
EventBus.getDefault().register(this);
//注册事件总线,在获取到eventbus单例后就可以注册了
//注册方法中有两个至关重要的方法:
//1. 寻找到当前object对象中所有带@Subscribe注解标记的方法并保存起来
//2. 对当前object对象中所有带@Subscribe注解的方法进行订阅
public void register(Object subscriber)
//获得当前对象的class对象
Class<?> subscriberClass = subscriber.getClass();
//通过subscriberMethodFinder对象查找到当前class对象下的所有方法,并存入集合
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//1
//程序锁
synchronized (this)
//将当前对象下的所有方法遍历
for (SubscriberMethod subscriberMethod : subscriberMethods)
//订阅(对象,方法)
subscribe(subscriber, subscriberMethod);//2
findSubscriberMethods(Class)
//缓存当前class对象和对应的所有方法的并发map
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
//查找对象下的所有方法的源码
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass)
//这里是一个缓存,将当前class对象缓存起来
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
//如果缓存中有,则直接使用缓存的数据
if (subscriberMethods != null)
return subscriberMethods;
//是否忽略生成的索引
if (ignoreGeneratedIndex)
//忽略,使用反射的方式查找subscriberMethods
subscriberMethods = findUsingReflection(subscriberClass);//1
else
//不忽略,使用信息的方式查找subscriberMethods
subscriberMethods = findUsingInfo(subscriberClass);//2
//如果当前缓存依然为努力了,则报错:当前传递进来的clas是对象没有附带@Subscribe注解对象
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;
findUsingReflection(class)
通过反射的方式查找subscriberMethods
FindState
static class FindState
//当前eventbus中记录的所有订阅者方法
final List<SubscriberMethod>subscriberMethods = new ArrayList<>();
//将同一个class的方法存放在同一个class中
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
//订阅者的方法key集合
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
//订阅者的class
Class<?> subscriberClass;
//当前传递进来的class
Class<?> clazz;
//是否跳过父类
boolean skipSuperClasses;
//订阅者信息
SubscriberInfo subscriberInfo;
//初始化
void initForSubscriber(Class<?> subscriberClass)
//订阅class和当前class为同一个
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级检查:只有事件类型的第一级(快速),如果需要,第二级有完整的签名。
//这里判断当前订阅服务器是否已经监听了相同的方法参数了
Object existing = anyMethodByEventType.put(eventType, method);
//没监听,则返回true
if (existing == null)
return true;
//已经监听过了该方法,则判断上一个保存的existing是否是Method
else
//如果existing对象是method类型,则订阅服务器则进行二次检查
if (existing instanceof Method)
//如果eventtype保存的上一个value依然不是当前方法和参数,则抛出异常
if (!checkAddWithMethodSignature((Method) existing, eventType))
// 抛出异常:非法状态
throw new IllegalStateException();
//官方解释:将任何非方法对象“消费”现有方法
//这一步的目的暂不清楚,走到这一步,则会返回true
anyMethodByEventType.put(eventType, this);
//
return checkAddWithMethodSignature(method, eventType);
//检查添加使用的方法签名:1,方法;2,参数的class对象
//该方法目的是判断当前方法和参数是否已经被存储起来了
//如果当前的key已经被某个class占用,则返回false
//如果当前的key没有被占用,或者key存储的class与传递进来的方法的依附class相同,则返回true
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType)
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());//方法名
methodKeyBuilder.append('>').append(eventType.getName());//参数名
//生成一个方法key,key = 方法名>参数名
String methodKey = methodKeyBuilder.toString();
//当前方法的类class对象
Class<?> methodClass = method.getDeclaringClass();
//将当前class对象存储到对应的key之下
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
//如果当前key没有被存储或者当前方法的类class对象是否是其父类
//有可能是为了防止在找父类时覆盖了子类的方法,因为此方法是子类是重写,方法名参数名完全一样(方法签名);
//另一个原因是可能是当一个类有多个方法监听同一个event(尽管一般不会这样做),也能将这些方法加进去。
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass))
return true;
else
//如果当前的methodKey已经有值,则这里返回的methodClassOld是上一个存储的值
//这里还原put,并且返回当前false,当前eventType参数已经保存过了
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
//清除父类class
void moveToSuperclass()
//如果清除父类class状态为true,则清空clazz
if (skipSuperClasses)
clazz = null;
else
//获得当前clazz的父类class
clazz = clazz.getSuperclass();
//获得当前clazz的父类class的名字
String clazzName = clazz.getName();
//直接清除当前类的系统级父类,这会提高性能,所有java和javax或者android.开头的都直接清空
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android."))
clazz = null;
//通过反射的方式查找subscriberMethods
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass)
//FindState状态初始化
FindState findState = prepareFindState();//1
//寻找状态初始化订阅者
findState.initForSubscriber(subscriberClass);
//如果findState中的class对象不为null,则一直继续循环
while (findState.clazz != null)
//使用反射的方式查找subscriberMethods
findUsingReflectionInSingleClass(findState);//3
//移除父类class
findState.moveToSuperclass();
//这个方法非常重要,一个是获取methods,另一个是释放findState里面的map信息
return getMethodsAndRelease(findState);//2
prepareFindState()
//真个EventBus中只存放4个FinsState对象
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
//初始化FindState
private FindState prepareFindState()
//同步锁,缓存当前class对象的并发map
synchronized (FIND_STATE_POOL)
//循环出所有的FindState对象
for (int i = 0; i < POOL_SIZE; i++)
FindState state = FIND_STATE_POOL[i];
if (state != null)
//先将map中的对象置空,这里置空为的是防止并发造成的互相干扰
FIND_STATE_POOL[i] = null;
//返回已保存的FindState对象
return state;
//map中没有对象则直接new一个FindState对象
return new FindState();
getMethodsAndRelease(FindState)
//这个方法非常重要,一是获取methods,二是释放findState里面的map信息
private List<SubscriberMethod> getMethodsAndRelease(FindState findState)
//将所有方法放入集合中
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
//清空findstate中存储的信息,上一步已经将findstate中subscriberMethods放入了集合中,所以这里清空没有问题
findState.recycle();//1
//同步锁
synchronized (FIND_STATE_POOL)
//这里的循环和之前的prepareFindState()方法相呼应
//简单来说即使一个复用池,如果当前FindState的数组中有空位置则存入FinsState对象
for (int i = 0; i < POOL_SIZE; i++)
//这里将findstate对象赋值,并发的时候这个复用池用的时候隔离,不用了回收
if (FIND_STATE_POOL[i] == null)
FIND_STATE_POOL[i] = findState;
break;
return subscriberMethods;
findUsingReflectionInSingleClass(FindState)
//使用反射的方式查找subscriberMethods
private void findUsingReflectionInSingleClass(FindState findState)
Method[] methods;//所有方法集合
try
//这比getMethods更快,特别是当订阅者是像activity这样的臃肿类时
//查找到所有不包含父类的public方法,有助于增加效率
methods = findState.clazz.getDeclaredMethods();
catch (Throwable th)
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
//如果报错这里再使用getMethods()
methods = findState.clazz.getMethods();
//跳过了父类方法
findState.skipSuperClasses = true;
//循环所有方法
for (Method method : methods)
//获得方法的修饰符
int modifiers = method.getModifiers();
//方法是public的且没有包含特定的修饰符
//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注解,详见@Subscribe标签介绍
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
//如果有该注解则继续往下走
if (subscribeAnnotation != null)
//获得当前方法的参数
Class<?> eventType = parameterTypes[0];
//检查当前方法和参数,如果没有被添加到eventbus中,则往下走
if (findState.checkAdd(method, eventType))
//获得当前订阅者要求的线程类型
ThreadMode threadMode = subscribeAnnotation.threadMode();
//subscriberMethods中新添加一个SubscriberMethod(方法,参数,线程类型,优先级,是否分发粘性事件)
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
//如果strictMethodVerification = true且当前方法有@Subscribe注解且参数不为1个,则抛出异常
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);
//如果strictMethodVerification = true;且当前方法带有注解@Subscribe则这里抛出异常
else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class))
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
//抛出异常:非法的@Subscribe方法:必须是公共的、非静态的和非抽象的方法
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
findUsingInfo(class)
使用方法信息查找subscriberMethods
//用于由注释处理创建的生成索引类的基类
public interface SubscriberInfo
Class<?> getSubscriberClass();
SubscriberMethod[] getSubscriberMethods();
SubscriberInfo getSuperSubscriberInfo();
boolean shouldCheckSuperclass();
//订阅者信息索引
//subscriberInfoIndexes是该对象的一个有序集合arraylist
public interface SubscriberInfoIndex
SubscriberInfo getSubscriberInfo(Class<?> subscriberClass);
//使用方法信息查找subscriberMethods
//EventBus 3.0刚加的功能,特点是比反射快
//在编译期完成subscriber的注册register,而不是在注册期间
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass)
//初始化
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null)
//获得订阅者的信息
findState.subscriberInfo = getSubscriberInfo(findState);//1
if (findState.subscriberInfo != null)
//获得订阅者订阅的所有方法,这一步很关键,如果没有存储某些方法,需要存储到subscriberMethods中
//获得当前订阅者信息里存储的所有订阅者方法
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array)
//依然检查当前eventbus是否存储了该方法和参数
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType))
//没有存储则存储到subscriberMethods中
findState.subscriberMethods.add(subscriberMethod);
else
//如果没有获取到订阅者信息,则依然使用反射的方法去获得findState
findUsingReflectionInSingleClass(findState);
//清除当前类的父类
findState.moveToSuperclass();
//返回所有当前类记录的需要订阅的方法并且清除Findstatus对象
return getMethodsAndRelease(findState);
getSubscriberInfo(FindState)
//获得订阅者的信息
private SubscriberInfo getSubscriberInfo(FindState findState)
//如果订阅者信息不为null并且订阅者的父类的信息也不为null
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null)
//将订阅者父类信息赋值给订阅者
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
//如果clazz和订阅者class一致,则返回订阅者信息
if (findState.clazz == superclassInfo.getSubscriberClass())
return superclassInfo;
//如果有订阅者信息索引则直接从索引中拿出来
if (subscriberInfoIndexes != null)
for (SubscriberInfoIndex index : subscriberInfoIndexes)
//从索引中获取当前findstate的class对象所存储的订阅者信息
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null)
return info;
return null;
这里有一个延申,订阅者信息索引的保存方法,EventBusBuilder中的addIndex(SubscriberInfoIndex)
注:源码中addIndex这个方法并没有用到,暂不清楚订阅者信息索引如何起作用的
subscribe(Object,SubscriberMethod)
当执行register的时候,会将当前注册的对象中的所有带有@Subscribe注解标记的方法都收集起来,上面这部 以上是关于EventBus3.0源码解析——03. register 注册的主要内容,如果未能解决你的问题,请参考以下文章