- 在理清原理之前,先要明白EventBus的使用场景和主要方法的调用,可以参考EventBus 3.0的使用。
- Publish/Subscribe模式,就是发布订阅模式。点击在线查看EventBus.java源码。EventBus的核心思想就是把event和订阅者,对应存在一个HashMap中,post方法调用后,再根据入参event,从HashMap中取出对应的订阅者对象,调用订阅方法,完成通信。
- 下面逐步分析EventBus的几个重要方法。
- getDefault()使用单例模式新建唯一单例EventBus实例。
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
- 在register()方法中,传入订阅者对象,获取该对象的类信息,在类信息中寻找包含注解@Subscribe的方法,产生一个方法列表subscriberMethods,
public void register(Object subscriber) {
//获取订阅者的类信息
Class> subscriberClass = subscriber.getClass();
//获取订阅者中所有的监听方法
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
- 如何根据@Subscribe注解找到对应方法?具体查找逻辑在SubscribeMethodFinder.java中,代码如下:
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");
}
}
}
- 再具体看subscirbe方法,到底在哪里添加的key-value键值对?
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
//在这里,hashMap添加元素
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;
}
}
...
}
- 存储元素后,post方法是怎么找到订阅者对象的?
答案是根据key值,取出List,遍历list,逐个发送event。订阅者对象存储在subscriptionsByEventType中,subscriptionsByEventType是一个HashMap,key的类型是Class>,value的类型是CopyOnWriteArrayList
private final Map, CopyOnWriteArrayList > subscriptionsByEventType;
post方法源码:
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List
更加详细代码分析,参考这篇:EventBus 3.0 源码分析



