简介
EventBus这东西相信很多人都用过,是一种用于Android的事件发布-订阅框架,由GreenRobot开发,官方地址是:EventBus。它简化了应用程序内各个组件之间进行通信的复杂度,尤其是Fragment之间进行通信的问题,可以避免由于使用广播通信而带来的诸多不便。
此处我们并不探究EventBus的使用方法,而是通过深入理解常用接口的内部逻辑来探究EventBus的整体内部构造,所以不熟悉EventBus的同学可以自行百度了解。
通过unregister方法了解订阅者(Subscriber)的缓存方式
首先我们先看unregister方法,一般反注册方法都是直接清除订阅者,所以通过unregister方法来查找到订阅者(Subscriber)的保存方式往往是最容易。
public class EventBus {
......
private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
private final Map
通过阅读上面源码,我们可以很容易的得到订阅者和事件的缓存方式:
- subscriptionsByEventType保存了事件类型以及Subscription列表键值对,事实上subscriptionsByEventType直接将事件类型、订阅者Subscribery以及订阅方法SubscriberMethod 联系在一起;此处完全可以大胆推测:发送事件是通过查找该事件类型对应的Subscription列表,然后遍历Subscription列表并一一触发对应的订阅者Subscriber中SubscriberMethod 方法的调用,最终实现事件发送。
-
typesBySubscriber保存了订阅者以及订阅者所订阅的事件类型列表键值对;typesBySubscriber主要是在反注册时用来辅助清理subscriptionsByEventType中的订阅者。
register方法究竟做了什么
看完unregister方法,我们可以大概的推测register(Object subscriber)里面主要做了什么:解析订阅者subscriber里面的带@Subscribe注解的方法,获取监听的事件类型,并将对应关系保存到subscriptionsByEventType和typesBySubscriber中!
public class EventBus {
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
*
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
public void register(Object subscriber) {
Class> subscriberClass = subscriber.getClass();
//查找订阅者subscriber内部的带@Subscribe注解的回调方法
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
//遍历监听者带@Subscribe注解的回调方法,进而获取并保存订阅者和事件类型对应关系
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//将subscriberMethod中的事件类型和订阅者对应关系保存到subscriptionsByEventType中
CopyOnWriteArrayList 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);
}
}
//根据subscriberMethod中所带的priority进行排序,以便后续发送事件时快速的按优先权排序发送
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;
}
}
//将订阅者subscriber和事件类型的对应关系保存到typesBySubscriber中
List> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) {//subscriberMethod被设置为接收粘性事件
if (eventInheritance) {//默认为true,考虑父类继承层级关系
// 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).
//必须考虑eventType的所有子类的现有粘性事件。
//注意:对大量粘性事件迭代所有事件可能效率低下,因此应更改数据结构以允许更有效的查找
//(例如,存储超类子类的附加映射:Class - > List )。
Set, Object>> entries = stickyEvents.entrySet();
for (Map.Entry, Object> entry : entries) {
Class> candidateEventType = entry.getKey();
//判断eventType是否为candidateEventType的父类
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
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());
}
}
}
上面代码中,我们可以很明显的看到register是如何保存订阅者和事件类型对应关系的,同时我们也知道了@Subscribe注解中priority 和sticky字段的作用。接下来我们继续查看上面跳过的重要一步,探究SubscriberMethod是如何被找到的:
class SubscriberMethodFinder {
List findSubscriberMethods(Class> subscriberClass) {
//从缓存中获取subscriber内部的订阅回调方法
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {//忽略索引,强制使用反射(默认false)
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;
}
}
private List findUsingReflection(Class> subscriberClass) {
//生成findState 对象并初始化
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//将subscriber中的SubscriberMethod信息封装到findState中
findUsingReflectionInSingleClass(findState);
//切换到父类,进入下个循环获取父类的SubscriberMethod信息
findState.moveToSuperclass();
}
//回收数据并返回SubscriberMethod列表
return getMethodsAndRelease(findState);
}
private List findUsingInfo(Class> subscriberClass) {
//生成findState 对象并初始化
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//从findState 和subscriberInfoIndexes中获取subscriberInfo 列表,
//但目前发现源码里面getSubscriberInfo(findState)返回的总是空的,
//索引的使用跟开发者的使用配置有关
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 {
/将subscriber中的SubscriberMethod信息通过反射封装到findState中
findUsingReflectionInSingleClass(findState);
}
//切换到父类,进入下个循环获取父类的SubscriberMethod信息
findState.moveToSuperclass();
}
//回收数据并返回SubscriberMethod列表
return getMethodsAndRelease(findState);
}
private SubscriberInfo getSubscriberInfo(FindState findState) {
//刚初始化的findState中findState.subscriberInfo总是空的
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
//subscriberInfoIndexes是由EventBus中的静态变量EventBusBuilder DEFAULT_BUILDER传递过来的,
//EventBusBuilder 中的addIndex(SubscriberInfoIndex index)没有任何地方调用,
//而且subscriberInfoIndexes也没有使用add方法添加数据,所以subscriberInfoIndexes一直都是空的
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
//这里一直都返回空,所谓的索引其实一直没用
return null;
}
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new 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) {//遍历所有方法
int modifiers = method.getModifiers();
//必须是public方法,不能是static和abstract方法
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class>[] parameterTypes = method.getParameterTypes();
//必须只能有一个参数
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
//必须添加@Subscribe注解
if (subscribeAnnotation != null) {
Class> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
//获取注解中的信息并封装到findState中
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");
}
}
}
private List getMethodsAndRelease(FindState findState) {
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;
}
static class FindState {
final List subscriberMethods = new ArrayList<>();
final Map anyMethodByEventType = new HashMap<>();
final Map subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class> subscriberClass;
Class> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
void recycle() {
subscriberMethods.clear();
anyMethodByEventType.clear();
subscriberClassByMethodKey.clear();
methodKeyBuilder.setLength(0);
subscriberClass = null;
clazz = null;
skipSuperClasses = false;
subscriberInfo = null;
}
boolean checkAdd(Method method, Class> eventType) {
// 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
// Usually a subscriber doesn't have methods listening to the same event type.
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
private boolean checkAddWithMethodSignature(Method method, Class> eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
Class> methodClass = method.getDeclaringClass();
Class> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
return true;
} else {
// Revert the put, old class is further down the class hierarchy
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
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;
}
}
}
}
}
SubscriberMethod的查找是EventBus的核心业务逻辑之一,仔细阅读源码后发现其实并不是很复杂,逻辑方法还是比较清晰的;唯一的问题是作者引入了索引的概念,但源码里面似乎并没有完全实现,索引逻辑没有真正的触发。索引流程必须得在开发者完成相关配置后才能跑。
事件的发送
看完了注册和反注册逻辑,接下来就是事件的发送了。其实了解完注册和反注册,我们基本上已经知道事件发送是怎么一回事了,无非就是拿着事件类型去subscriptionsByEventType中获取该类型事件的订阅者列表,然后遍历列表触发SubscriberMethod的调用,唯一值得期待的就只有注解中的线程模式的处理。废话不多说,继续看源码:
public class EventBus {
/** Posts the given event to the event bus. */
public void post(Object event) {
//获取当前发送状态
PostingThreadState postingState = currentPostingThreadState.get();
//事件添加到发送队列
List
看完上面的代码,我们总结一下事件的发送流程:
1、将新的事件添加的发送队列中,然后判断是否正在发送事件:如果是则不做其他处理,发送队列中事件会自动发送;如果不是则触发事件发送逻辑并标记为正在发送。进入发送状态后,发送队列中的事件会被一一发送直到队列为空。队列事件发送完了,标记为未发送状态。
2、从队列中拿出待发送事件,通过查看事件event继承的父类层级关系来确认有几个事件类型,然后再根据事件类型的个数来确认事件event发几次。
3、根据各个事件类型获取订阅者列表,然后一一触发订阅者的SubscriberMethod方法,进而触发回调。SubscriberMethod的触发涉及到线程的处理,不过这里面的线程处理都是最基础的处理方式,没有什么特别值得深究的。mainThreadPoster是继承Handler;asyncPoster和backgroundPoster都是继承Runnable,然后都被提交到线程池executorService中运行。