EventBus是基于发布/订阅的开源框架,主要用于组件之间的通信,下面会从三个点对EventBus的源码进行分析
(1)register(Object subscriber) 被通知类的注册
使用EventBus时我们首先会在需要被通知的类中去进行注册,现在看一下register()里面做了什么事。
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
在register中会通过findSubscriberMethods方法得到一个SubscriberMethod的列表,来看一下查找方法的实现。
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;
}
}
方法内部首先会以subscriberClass,也就是注册的类对象为key,在METHOD_CACHE中查找对应的SubscriberMethod集合,如果有则返回,没有的话则会通过两种方式去查找,一种是通过反射的方法,另一种是通过索引文件的方式,这边只看使用反射方式查找并缓存。
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
//精简之后的代码
private void findUsingReflectionInSingleClass(FindState findState) {
methods = findState.clazz.getDeclaredMethods();
for (Method method : methods) {
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
通过反射的方式找到目标方法集合,然后遍历集合将method、eventType、threadMode等信息构建成一个SubscriberMethod填充到findState中,最后将SubscriberMethod的集合返回,将findState释放并放入到池中。
查找过程进行完成之后紧接着来了SubscriberMethod的遍历操作,通过subscribe方法对目标方法和类对象进行关联。
(2)post(Object event) 通知事件发送
当我们需要通信的时候,会通过post(event)的方式进行通知,然后注册的目标类就会收到相应的通知。
public void post(Object event) {
// 省略n行代码
try {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
方法内部就是通过postSingleEvent方法进行事件发送,继续跟进这个方法。
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
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);
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
for (Subscription subscription : subscriptions) {
postToSubscription(subscription, event, postingState.isMainThread);
}
通过event找到关联的类集合,通过postToSubscription方法遍历的对目标类进行通知。
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
//省略。。。
invokeSubscriber(subscription, event);
}
最后通过反射的方式对目标方法进行调用
(3)ThreadMode 事件触发所在线程
在目标类中定义事件方法,一般会通过ThreadMode指定方法触发所在的线程。
在register过程中会将ThreadMode的信息封装到subscriberMethod中。来看一下具体的代码:
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;
}
}
事件发送的时候首先会通过对ThreadMode的判断进行不同的操作。来看一下四种不同的模式有什么不同
MAIN
如果post所在的线程是主线程,那么直接通过反射去调用目标方法;如果所在的线程为工作线程,则会通过Handler将线程转换到主线程中。
POSTING
事件触发所在的线程与事件发送所在的线程一致
BACKGROUND
如果post所在的线程是主线程,那么会重新创建一个工作线程进行方法调用;如果所在的线程为工作线程,则不会创建额外的线程,直接在当前线程中进行调用
ASYNC
无论post所在的线程如何,都会额外去创建一个工作线程去进行方法调用。
这是EventBus大体的工作流程,当然还有部分细节没有去分析,有兴趣的可以自行阅读。