前言
上篇文章笔者简单介绍了 EventBus 的用法。本篇文章笔者将简单分析 EventBus 的源码。从上篇文章我们可以得知,要使用 EventBus 首先要调用 EventBus 的 register 方法注册(一般在 onCreate 方法中)。然后,定义被 Subscribe 注解的方法(用来接收由 post 方法发送的消息)。最后,调用 unregister 方法解注册(一般在 onDestroy 方法中)。所以,笔者注重分析 EventBus 的 register , post 方法的实现,以及 EventBus 是如何调用接收消息的方法的。
register
EventBus.getDefault().register(this);
我们一般调用上述代码进行注册,调用上述代码的类我们暂且称为注册类。其中 getDefault 方法获取 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);
}
}
}
先来看 3 , 4 行:这里调用 subscriberMethodFinder.findSubscriberMethods(subscriberClass)
得到一个 SubscriberMethod 的 List 。其中 SubscriberMethod 是对注册类中接收消息的方法的 Method 对象的封装。subscriberMethodFinder 是 SubscriberMethodFinder 类型的,我们接着追踪 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 行:List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
其中 METHOD_CACHE 是 Map
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();
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");
}
}
}
由上述代码可以看出,findUsingReflectionInSingleClass 获取注册类中定义的方法并且遍历这些方法,然后把 public 、非 static 、非 abstract 、非 synthetic 、一个参数的、并且被注解 Subscribe 标注的方法封装成 SubscriberMethod 对象。并添加到 List subscriberMethods 中。然后把 subscriberMethods 返回给 findUsingInfo 方法,并最终返回给 EventBus 的 register 方法。接下来我们重新回到 register 方法。
register 方法中第 6 7 8 行 对返回的 List subscriberMethods 的遍历并调用 subscribe 方法。subscribe 方法的源码如下:
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
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++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
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 方法中,把
subscriberMethod 和注册类对象封装成 Subscription 对象 newSubscription 。 并将 newSubscription 添加到 CopyOnWriteArrayList subscriptions 中并且通过 subscriberMethod.priority 确定 newSubscription 在 subscriptions 中的位置。subscriberMethod.priority 其实就是方法执行的优先级。需要注意的是,subscriptions 会被保存到 subscriptionsByEventType 中,subscriptionsByEventType 是一个 Map ,其 key 是注册类中被注解的方法的参数的类型,也就是接受消息的方法的参数的类型。 至此 register 方法大概介绍完毕。下面来看 post 方法。
post
EventBus 的 post 方法 是 EventBus 用来发布消息的方法。 post 方法被调用后会将 post 方法的参数传递给相应的注册类中的相应的方法中,并调用此方法。这个过程是怎样的呢?请看 post 的源码:
/** Posts the given event to the event bus. */
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
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 {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
由上述源码可以看出,第 4 , 5 行把 post 方法的参数添加到一个 List 中。第 8 行得到 post 方法是否是在 mian 线程中调用的。第 14 15 16 行对保存 post 方法参数的 List 遍历删除并调用 postSingleEvent 方法。在 postSingleEvent 方法中会调用 postSingleEventForEventType 方法。postSingleEventForEventType 方法的源码如下:
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.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;
}
在 postSingleEventForEventType 方法中通过参数的类型获取 subscriptionsByEventType 中相应的 Subscription 的 CopyOnWriteArrayList subscriptions。如果 subscriptions 不为空则遍历它,并调用 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);
}
}
由上述代码可以看出,postToSubscription 通过注解 Subscription 的属性 threadMode 的值,决定相应的接受信息的方法在哪个线程里调用。调用的规则已经在上篇文章中阐述过,这里不再赘述。invokeSubscriber 方法其实就是利用反射来实现接受信息的方法的调用的,这里也不再详细说明。
总结
EventBus 的实现其实就是一个典型的观察者模式。注册类向 EventBus 注册,当有消息需要发送的时候 EventBus 通过 post 方法向注册者们分发消息,其实就是遍历调用注册类中符合要求的方法。