if (info != null) {
return info;
}
}
}
return null;
}
所以findUsingInfo()
的while循环里直接走了else分支:findUsingReflectionInSingleClass(findState)
。
也就是说findUsingInfo()方法的主要逻辑是由findUsingReflectionInSingleClass()方法去完成的(默认情况,不考虑使用apt)
这里有个细节要看一下:
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();
}
这个while循环什么时候结束呢?这是我们第一次看EventBus源码看到这里比较疑惑的地方,答案就在这个 findState.moveToSuperclass()
里面:
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;
}
}
}
我们可以看到这里clazz赋值为它的超类,直到没有父类为止,才返回clazz=null
,循环也才终止。也就是说 这个while循环保证了,获取注解的方法不仅会从当前注册对象里去找,也会去从他的父类查找。
好了,继续分析findUsingReflectionInSingleClass(findState)
方法:
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) {
// 获取该方法的修饰符,即public、private等
int modifiers = method.getModifiers();
// 修饰符是public才会走该分支
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
// 这里是获取该方法的参数类型,String,in
Class<?>[] parameterTypes = method.getParameterTypes();
// 只有一个参数会走该分支
if (parameterTypes.length == 1) {
// 如果该方法被@subscribe注解会走该分支
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
// 获取传入的对象的Class
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");
}
}
}
findUsingReflectionInSingleClass()方法首先通过反射去拿到当前注册对象的所有的方法,然后去进行遍历,并进行第一次过滤,只针对修饰符是Public的方法,之后进行了第二次过滤,判断了方法的参数的个数是不是只有一个,如果满足,才去进一步的获取被@subscribe注解的方法。
然后调用
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,subscribeAnnotation.priority(), subscribeAnnotation.sticky()))
这行代码,new了一个SubscriberMethod()对象,传入参数,并添加到 findState.subscriberMethods的集合中去.
static class FindState {
final List subscriberMethods = new ArrayList<>();
}
之后,findUsingInfo()
的getMethodsAndRelease(findState)
方法回去获取刚刚设置的findState
的subscriberMethods
集合,并把它return出去。代码如下:
private List getMethodsAndRelease(FindState findState) {
// 对subscriberMethods进行了赋值,return出去
List subscriberMethods = new ArrayList<>(findState.subscriberMethods);
// 进行了回收
findState.recycle();
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;
}
步骤1总结:至此,以上就是EventBus获取一个注册对象的所有的被@subscribe注解的方法的集合的一个过程。该过程的主要方法流程为:
(1) subscriberMethodFinder.findSubscriberMethods()
(2) findUsingInfo()
(3) findUsingReflectionInSingleClass()
步骤2
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
通过步骤1,我们已经拿到了注册对象的所有的被@subscribe注解的方法的集合的。现在我们看看subscribe()都做了哪些 操作。
我们不妨想想,如果我们要去做subscribe()时,我们要考虑哪些问题,第一个问题是,要判断一下这些方法是不是已经注册过该事件了要不要考虑方法名是不是相同的问题。第二个问题是一个注册对象中有多个方法注册了该事件,我们该怎么保存这些方法,比如说事件类型是String,一个Activity里有两个方法注册了该事件,分别是onEvent1和onEvent2,那我是不是应该用一个Map集合,以事件类型为key,把onEvent1和onEvent2放到一个List集合中,把该List集合作为value。
subscribe()方法:
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
// 拿到事件event类型,比如是String或者自定义的对象
Class<?> eventType = subscriberMethod.eventType;
// Subscription将注册对象和subscriberMethod 做为参数传入
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// subscriptionsByEventType是一个Map集合,key是事件类型,验证了我上面的猜想
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
// 如果subscriptions是null,则new出一个CopyOnWriteArrayList,并且往Map集合中添加
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
// 这里做了if语句判断,判断一下List集合中是否存在,存在就抛异常
// 如果不存在?怎么没有add操作? 保持疑问
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
- eventType);
}
}
以上的操作验证了我之前的猜想,通过if (subscriptions.contains(newSubscription)) 这个if语句判断 是否发生了重复注册,注意这里重复注册的含义是 事件类型一致,以及方法名也一致。
接下来我们看看如果一个注册对象重复注册了事件Event(方法名不能一致),优先级priority是如何设置的
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
// 这里判断subscriberMethod的优先级是否是大于集合中的subscriberMethod的优先级,如果是,把newSubscription插进去
// 这也表明了subscription中priority大的在前,这样在事件分发时就会先获取。
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
if语句的条件subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) ,保证了subscription中priority大的在前。同时i == size 这个条件也保证了priority小的也会添加到subscriptions集合中去
紧接着我们看看EventBus是如何处理粘性事件的:
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).
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);
}
}
}
注意以上代码有四行比较重要的注释信息。大致的意思是必须考虑eventType所有子类的现有粘性事件,在迭代的过程中,所有的event可能会因为大量的sticky events变得低效,为了使得查询变得高效应该改变数据结构。
isAssignableFrom方法的意思是判断candidateEventType是不是eventType的子类或者子接口,如果postSticky()的参数是子Event,那么@Subscribe注解方法中的参数是父Event也可以接收到此消息。
拿到粘性Event后,调用了checkPostStickyEventToSubscription()
方法,改方法内部方法内部调用了postToSubscription()
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
// --> Strange corner case, which we don’t take care of here.
postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
}
}
步骤2总结:至此,EventBus的注册操作已经全部分析完了,需要注意的是,粘性事件是在subscribe中进行post的
(二) 发送事件:EventBus.getDefault().post(xxx);
普通Event
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List eventQueue = postingState.eventQueue;
// 将Event添加到List集合中去
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException(“Internal error. Abort state was not reset”);
}
try {
// 遍历这个list集合,条件是集合是否是空的
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
首先将当前的 Event添加到eventQueue
中去,并且while循环,处理post每一个Event事件,调用的是 postSingleEvent(eventQueue.remove(0), postingState)
:
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
// 获取Event的Class对象
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
// eventInheritance初始化的时候值为true,所以会走该分支
if (eventInheritance) {
// 获取当前的Event的Class对象的所有父类的Class对象集合,优先从缓存里读取。
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
…
…
}
这里lookupAllEventTypes()
方法也是为了获取当前的Event的Class对象的所有父类的Class对象集合,优先从缓存里读取。之后是 for循环获取到的Class对象集合,调用postSingleEventForEventType()
方法:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList subscriptions;
synchronized (this) {
// subscriptionsByEventType该map是在subscribe()方法中进行了put操作
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
// 进行for循环并调用了postToSubscription()
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
postSingleEventForEventType()
方法,主要是获取Event的Class对象所对应的一个List集合,集合的对象是Subscription参数。subscriptionsByEventType对象是在subscribe()方法中进行了赋值。for循环CopyOnWriteArrayList集合,并调用postToSubscription()
线程模型
等执行到postToSubscription()
方法时,线程模型才派上了用场。
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
第一个分支:线程模型是POSTING,直接调用了invokeSubscriber()
方法。
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException(“Unexpected exception”, e);
}
}
很明显的看到,这是基于反射去调用方法,invoke方法接收两个参数,第一个参数是注册的对象,第二个参数是事件的Event。
从这里就可以看出来,POST并没有去做线程的调度什么的,事件处理函数的线程跟发布事件的线程在同一个线程。
第二个分支:线程模型是MAIN 首先判断了下事件发布的线程是不是主线程,如果是,执行invokeSubscriber()
方法,invokeSubscriber()
上面已经分析过,如果不是主线程,执行mainThreadPoster.enqueue(subscription, event)
。mainThreadPoster
是继承自Handler
,从这里大概可以猜到,这一步是去做线程调度的。/font>
我们看一看mainThreadPoster
的enqueue
做了什么事:
void enqueue(Subscription subscription, Object event) {
// 封装了一个PendIngPost
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
// 将PendIngPost压入队列
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
// 调用了sendMessage()
if (!sendMessage(obtainMessage())) {
throw new EventBusException(“Could not send handler message”);
}
}
}
}
enqueue()
主要封装了一个PendingPost
类,并把subscription
和event
作为参数传进去,紧接着把PendingPost
压入到队列中去,然后sendMessage
发了一条消息。
熟悉Handler机制的同学知道,处理消息是在handleMessage()方法中完成的:
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException(“Could not send handler message”);
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
代码有点多,我们主要看一下,它接收到消息后,是做了什么处理。从队列中取了消息,并且调用了eventBus.invokeSubscriber(pendingPost)
方法,回到EventBus类中。
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
invokeSubscriber(subscription, event);
}
}
该方法内部还是去调用了invokeSubscriber()
方法。
分析完线程模型为MAIN 的工作流程,不难做出结论,当发布事件所在的线程是在主线程时,我们不需要做线程调度,直接调用反射方法去执行。如果发布事件所在的线程不是在主线程,需要使用Handler做线程的调度,并最终调用反射方法去执行
第三个分支:线程模型是BACKGROUND。如果事件发布的线程是在主线程,执行backgroundPoster.enqueue(subscription, event)
,否则执行invokeSubscriber()
。
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
将PendingPost
对象压入队列,然后调用eventBus.getExecutorService().execute(this)
,交给线程池去进行处理,它的处理是在Runnable的run()
中。backgroundPoster
实现了Runable
接口:
@Override
public void run() {
try {
try {
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
Log.w(“Event”, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
最重要的还是eventBus.invokeSubscriber(pendingPost)
这行代码,上面已经分析过。
第四个分支:线程模型是ASYNC。直接调用 asyncPoster.enqueue(subscription, event)
,asyncPoster
也是实现了Runnable
接口,里面也是使用的线程池,具体的操作就不分析了,感兴趣的可以去看一下源码,跟上一步操作类似。
(三) 高级用法
EventBus3.0较之前的版本有了一次改造,在3.0之后增加了注解处理器,在程序的编译时候,就可以根据注解生成相对应的代码,相对于之前的直接通过运行时反射,大大提高了程序的运行效率,但是在3.0默认的还是通过反射去查找用@Subscribe标注的方法,一般在使用的时候基本都是这个模式。 那我们怎么配置让EventBus使用注解器生成的代码呢? EventBus官网apt介绍
在这里我们重点提一下 EventBusBuilder类的:
boolean ignoreGeneratedIndex;
List subscriberInfoIndexes;
subscriberInfoIndexes
变量可以去使用注解处理器生成的代码。SubscriberInfoIndex
就是一个接口,而注解生成器生成的类也是继承的它,我们也可以自己去继承它,定制自己的需求,不需要反射的EventBus。
我们再回过头来看一下注册过程的findUsingInfo()
方法:
private List 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);
}
我们在前面分析的时候,直接分析的 findUsingReflectionInSingleClass(findState)
方法,因为getSubscriberInfo()
返回null,那什么时候getSubscriberInfo()
返回不为null呢 ? 我们具体看看getSubscriberInfo()
。