最近感觉遇到了瓶颈,简单的东西不想做,难的东西做不出来,比如设计模式,设计思想,框架搭建等,这些自己虽然能看懂,也会用,但是到了实际工作中,就懵了,所以想通过分析一些框架的源码来加强这部分的弱点和痛处,希望之后回过头来能感觉自己学到很多东西。
现在就EventBus这个开源项目进行分析,目前已更新到3.1.1.网上有很多分析的文章,比较全面的是这一篇EventBus源码分析,我也略作参考,但是自己打算对于各个细节和写的比较好的地方都说明一下,所以篇幅可能会很长,内容也会分多篇,由于工作,也可能需要耗费较长的时间来分析,每周更新吧。就这样,开始了。
github地址:https://github.com/greenrobot/EventBus
先放一张官方流程图和介绍:
EventBus: Events for Android
EventBus is an open-source library for Android and Java using the publisher/subscriber pattern for loose coupling. EventBus enables central communication to decoupled classes with just a few lines of code – simplifying the code, removing dependencies, and speeding up app development.
翻译下:EventBus是一个用于Android和Java的开源库,使用发布/订阅模式实现松耦合,EventBus允许中央通信只需几行代码就可以解耦类——简化代码,消除依赖,并且增加应用程序开发速度。
流程图分析:订阅者关联到EventBus,存储下来,也就是resgister.发布者发送消息的时候,将事件发送到EventBus,再由EventBus分发到订阅者,订阅者通过onEvent()方法来接受到消息,从而处理数据。
//todo
首先分析EventBus.getDefault().register(this)这个方法。
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods =
subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
看第3行的方法,findSubscriberMethods()这个是从方法缓存队列里取到当前这个类的反射方法。
SubscriberMethod :是反射方法类,包含优先级,具体方法,响应事件等。
SubscriberMethodFinder:反射方法查询器
再看看findSubscriberMethods()这个方法的具体实现
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;
}
}
这个方法首先从缓存中取类的方法集合,如果有,直接返回,否则通过反射或者类信息去查找。
如果2种方式都没有找到,则说明没有定义一个@Subscribe的注解方法,或者定义的方法有问题.走到下面判空时就会抛出异常.
比如下面这种,方法中带有2个参数:
@Subscribe
public void onEventMainThread(EventInfo eventInfo,String msg) {
Log.d("Event", eventInfo.getName());
}
如果找到了注解的方法,则添加进缓存,添加方式key=类,value=注解的方法.
优点:METHOD_CHCHE是一个ConcurrentHashMap,它是支持并发和线程安全的,这里因为读取次数可能较多,用这个集合比HashMap来说要安全高效.
ignoreGeneratedIndex这个boolean是强制调用反射,目前赋值的地方还没有找到,这个变量属于EventBusBuilder里的一个属性.
接下来分析findUsingReflection()这个方法,
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();//准备查询标记
findState.initForSubscriber(subscriberClass);//初始化订阅者
while (findState.clazz != null) {//遍历所有的方法
findUsingReflectionInSingleClass(findState);//开始反射
findState.moveToSuperclass();//位移到一个方法
}
return getMethodsAndRelease(findState);//使用完之后释放
}
具体的反射方法是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();//获取注解方法的类型,private还是 public
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");
}
}
}
使用过EventBus的coder应该知道EventBus规定注解的方法必须是public并且方法上所带的参数仅有且必须有一个,这个方法就是其实现.通过method.getModifiers()获取其属性,如果不是public的方法,则抛出EventBusException异常.异常里的英文已经说的很明确了,必须是public,不能加static,abstract.
然后通过method.getParameterTypes();获取到注解方法的参数数量,如果没有参数或者参数在一个以上。也会抛出异常.