源码分析
EventBus 是一款在 Android 开发中使用的发布/订阅事件总线框架,基于观察者模式,将事件的接收者和发送者分开,简化了组件之间的通信,使用简单、效率高、体积小!
分析它的源码,我们先从获取实例入手,然后分析下它的register方法,unregister方法和post方法的实现细节。
1、获取实例
一般我们都是通过getDefault方法直接获取到EventBus的默认实例,getDefault方法内部是用了一个默认的EventBusBuilder(DEFAULT_BUILDER)来创建EventBus,当然,我们也可以通过EventBus的builder()方法获取到EventBusBuilder实例,从而来构建符合我们自己需求的EventBus实例。
// 默认的EventBusBuilder
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
// 静态单例
static volatile EventBus defaultInstance;
public static EventBus getDefault() {
EventBus instance = defaultInstance;
// 单例模式获取实例
...
instance = EventBus.defaultInstance = new EventBus();
}
return instance;
}
// 获取EventBusBuilder实例
public static EventBusBuilder builder() {
return new EventBusBuilder();
}
// 默认构造,使用默认的EventBusBuilder
public EventBus() {
this(DEFAULT_BUILDER);
}
// 调用该构造创建实例
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
...
}
2、注册(register)
public void register(Object subscriber) {
// 获取订阅类(注册类)的class对象
Class<?> subscriberClass = subscriber.getClass();
// 找到该类中所有的订阅了事件的方法(以下称订阅方法)集合(即使用@Subscribe注解修饰的方法)
// SubscriberMethod内部包含订阅方法的信息(线程模式、优先级、事件类型、是否是粘性事件等)
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
// 遍历订阅方法集合,以完成订阅
for (SubscriberMethod subscriberMethod : subscriberMethods) {
// 传入订阅类和订阅方法
subscribe(subscriber, subscriberMethod);
}
}
}
register方法的大概流程是通过订阅类对象找到该类中所有被@Subscribe注解修饰的方法,然后通过subscribe方法完成方法的订阅,接下来看下findSubscriberMethods内部的实现:
// 查询订阅类中所有的订阅方法,返回订阅方法集合
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
// METHOD_CACHE是个ConcurrentHashMap,线程安全
// 查找METHOD_CACHE中是否已存在订阅类的订阅方法的集合
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
// 如果有,则直接返回,避免重复查找
if (subscriberMethods != null) {
return subscriberMethods;
}
// ignoreGeneratedIndex是否忽略注解生成器,默认为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 {
// 将订阅类作为key,订阅方法的集合作为value存入Map
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
// 默认是调用了findUsingInfo方法
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
// 获取FindState(相当于一个辅助类),从FIND_STATE_POOL池中取,如果没有则创建个实例
FindState findState = prepareFindState();
// 将订阅类的引用存入FindState
findState.initForSubscriber(subscriberClass);
// 循环直到findState的clazz为空(clazz为java.或android.或javax.等系统类则结束查找)
while (findState.clazz != null) {
// 由于subscriberInfoIndexes()为空,则该方法就返回null
// subscriberInfoIndexes(注解处理器生成的索引类),通过EventBus.builder().addIndex(索引类).build()添加进来,这个索引类后面再单独分析下
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);
}
// 将clazz指向订阅类的父类,直到找到java.或android.或javax.等系统类,则返回null
findState.moveToSuperclass();
}
// 获取订阅方法集合并释放FindState
return getMethodsAndRelease(findState);
}
// 通过反射获取类的订阅方法
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
// 使用getDeclaredMethods相对于getMethods效率高点,因为只获取当前类的所有方法,而getMethods还会获取父类中的方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
// 在部分手机使用getDeclaredMethods会报NoClassDefFoundError异常,所以抛异常的话就使用getMethods获取类的所有方法
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
// 遍历所有的方法
for (Method method : methods) {
// 获取方法的修饰符对应的整数值
int modifiers = method.getModifiers();
// 判断该方法是public,不是ABSTRACT、STATIC等修饰的方法
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
// 获取方法上的参数
Class<?>[] parameterTypes = method.getParameterTypes();
// 判断是否只有一个参数
if (parameterTypes.length == 1) {
// 获取方法的注解类型为Subscribe
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
// 判断是否存在Subscribe注解
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0]; // 获取事件类型
// 判断findState的map中是否存在该添加过该事件类型为key的数据
if (findState.checkAdd(method, eventType)) {
// 获取注解上的线程模式,默认是POSTING,即在当前运行的线程
ThreadMode threadMode = subscribeAnnotation.threadMode();
// 构造SubscriberMethod,存入findState的订阅方法集合中
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");
}
}
}
到这里,我们就获取到了该订阅类中的所有订阅方法,那我们回到register方法,遍历了所有的订阅方法,然后调用了subscribe方法:
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
// 获取订阅方法中的事件类型
Class<?> eventType = subscriberMethod.eventType;
// 构造Subscription,包含订阅者和订阅方法信息(以下称订阅信息对象)
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// 通过事件类型获取使用该事件类型的订阅信息对象的集合,subscriptionsByEventType是一个key为事件类型,value为该事件类型对应的订阅信息对象的集合
// 这里划重点,后面post方法就通过这个map来获取所有使用了该事件类型的订阅信息对象,从而通过invoke对应的方法
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
// 没有找到事件类型对应的订阅信息对象的List
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>(); // 新建
subscriptionsByEventType.put(eventType, subscriptions);
} else {
// 事件类型对应的订阅信息对象集合中已包含了该Subscription对象,则抛出异常
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
int size = subscriptions.size();
// 遍历事件类型对应的订阅信息对象的集合
for (int i = 0; i <= size; i++) {
// 根据优先级插入新构造的Subscription(订阅信息对象)
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
// typesBySubscriber是一个key为订阅者,value为该订阅者中的所有事件类型组成的集合,作用是在反注册时移除该订阅者的订阅方法
// 通过订阅者,获取其内部的所有的事件类型的集合
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<Class>).
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);
}
}
}
这里subscribe方法主要是配置了两个map的数据,subscriptionsByEventType和typesBySubscriber,还有粘性事件的处理,subscriptionsByEventType存储了事件类型与其对应的订阅信息对象集合的映射,用于通过事件类型去找到所有的订阅方法,从而进行方法的调用,typesBySubscriber存储了订阅类与其所有事件类型的映射,用于反注册中解除订阅关系。
3、反注册(unregister)
// 反注册
public synchronized void unregister(Object subscriber) {
// 获取该订阅者中的所有事件类型的集合
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
// 遍历事件类型的集合
for (Class<?> eventType : subscribedTypes) {
// 通过事件类型找到对应的订阅者,将该数据从subscriptionsByEventType中移出
unsubscribeByEventType(subscriber, eventType);
}
// 将该订阅者移出Map
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
// 通过事件类型,获取所有使用了该事件类型的订阅方法的集合
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
// 遍历订阅信息对象集合
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
// 找到该事件类型的订阅者,移出Map
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
反注册主要的处理就是将该订阅类的所有订阅信息从对应的Map中移出。
4、发送事件(post)
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
// 发送事件方法
public void post(Object event) {
// currentPostingThreadState是个存储PostingThreadState的ThreadLocal
// PostingThreadState包含事件队列、当前是否是主线程等信息
PostingThreadState postingState = currentPostingThreadState.get();
// 获取当前事件队列
List<Object> eventQueue = postingState.eventQueue;
// 将当前要发送的事件添加进队列集合
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread(); // 是否是主线程
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
// 循环发送事件
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass(); // 获取当前事件类型
boolean subscriptionFound = false; // 是否找到对应的订阅信息对象
// eventInheritance标识是否需要查找该事件的父类
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 {
// 通过事件类型查找是否有对应的订阅信息对象,如果有,则调用方法,并返回true
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
// 如果找不到事件,则抛出异常
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
// 获取该事件类型的订阅信息对象的集合
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
// 遍历该事件类型对应的订阅信息对象
for (Subscription subscription : subscriptions) {
// 给postingState赋值对应的事件和subscription
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
// 根据不同的线程模式调用订阅方法
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;
}
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 {
// 利用Handler发送到主线程执行,最终也是执行invokeSubscriber方法
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED: // 主线程执行,但事件会先进入队列,不同的线程发送消息,先加入队列的会优先执行
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND: // 子线程执行
if (isMainThread) {
// 实现Runnable,最终通过EventBus的ExecutorService(线程池)执行
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);
}
}
// 最终调用的唤醒订阅类中的订阅方法
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);
}
}
发送事件的时候,首先是根据事件类型的对象去查找对应的订阅信息对象的集合,找到后遍历该集合,再根据不同的线程模式去调用订阅方法。
总结
EventBus的发送和接收事件,主要是通过subscriptionsByEventType这个Map来实现,注册的时候往里面存入订阅信息对象数据,而当发送事件时,从这个Map中查询到对应事件的订阅信息对象,然后通过不同的线程模式去触发对应的方法。typesBySubscriber这个Map存储了订阅类中的所有订阅事件类型,从而可以在反注册时,查询到对应的订阅类数据,然后将它从subscriptionsByEventType中移出。粘性事件和注解处理器生成的索引类放到后面再分析。