EventBus介绍:
EventBus出自greenrobot,和之前大名鼎鼎的GreenDao出自同一家。今天我们将学习分析Event 3.0,EventBus 3.0 最新的特性就是加入了注解,通过注解的方式 告知订阅函数运行在哪个线程中,是一种发布订阅设计模式(观察者设计模式)。。
github地址:https://github.com/greenrobot/EventBus
官方文档:http://greenrobot.org/eventbus/documentation
EventBus的注册过程总结为:class ->找到注解方法method->map.put (class ,method)->注册完成。
在EventBus的注册过程可以发现,当传入的对象子类或者本身方法特别多的时候注册过程会很慢而且很占内存。
下面通过解析注册过程来证明这一点
EventBus使用之前首先需要能过EventBus.getDefault().register(this)注册,才能收到发送的消息
注册过程:
将当前对象通过register 传入
public void register(Object subscriber) {
//获取当前对象的class
Class<?> subscriberClass = subscriber.getClass();
能过当时类查询当前对象里面是添加过注解的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
findSubscriberMethods方法源码如下:
判断类中是否有注册的方法,如果有赐返回,
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
是否有强制索引/默认为false
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;
}
下面看一下findUsingInfo方法的实现
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
判断是否有子类,如果有子类将子类中的添加过注册的方法添加到Map中
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);
findUsingReflectionInSingleClass 获取当前对象所有添加注册的方法
代码如下:
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();
方法是否是公共的
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
方法的参数
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {//可以看出在发送消息时,一定要有一个参数。
获取注解方法,并将方法以class,方法名缓存到MAP中
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");
}
}
再看注册方法
synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } }
将所有的注册方法以class为KEY,方法为Value保存到内存中,以方便后面事件调用
EventBus 事件发送
将object 能过EventBus.getDefault().post(object)发送出来,在EventBus内部的实现是将参数object 做为key向缓存中找到以此做key的方法,然后通过Invoke方法去执行并将参数传下(在主线程中)
原码流转如下:
post->postSingleEvent->postSingleEventForEventType->postToSubscription->invoke
当注解方法不在主线程里,发送的事件首先放在消息队列中,然后通过不停的对消息队列的读取通过invoke来调用。在注册的时候发将消息队列读消息队列的线程处于运行状态中。
最后eventBus 解注册将key对象从缓存中移除