上一篇中我们讲解了EventBus的使用,传送门:https://www.jianshu.com/p/1e624bf9144d
这篇我们从源码出发一步一步解析EventBus实现原理。
这里先列出一个大纲,接下来会大致根据这个大纲一步一步深入剖析:
1.获取EventBus实例;
2.注册订阅者;
3.书写接收订阅事件的方法;
4.发送事件给订阅者;
5.注销;
1.获取EventBus实例
1)EventBus mEventBus = EventBus.getDefault();
2)EventBus eventBus = EventBus.builder()
.logNoSubscriberMessages(false)
.sendNoSubscriberEvent(false)
.build();
1)跟着源码进去:
/**
* Convenience singleton for apps using a process-wide EventBus instance.
* 双重检查
*/
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
/**
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use acentral bus, consider {@link #getDefault()}.
* 创建一个新的 EventBus 实例,每个实例在 events 事件被发送的时候都是一个单独的领域,为了使用一个 事件总线,考虑用 getDefault() 构建。
*/
public EventBus() {
this(DEFAULT_BUILDER);
}
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
单例模式,后面我会单独抽出一篇来说,这里略过。
这里来看看EventBus的成员变量及构造函数:
- 成员变量:
static volatile EventBus defaultInstance; // 单例采用 volatile 修饰符,会降低性能,但能保证EventBus每次取值都是从主内存中读取
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
// 发送 post 事件的 map 缓存
private static final Map, List>> eventTypesCache = new HashMap<>();
// key 为事件类型,value为封装订阅者和订阅方法的对象的集合
private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
// key为订阅者,value为eventType的List集合,用来存放订阅者中的事件类型
private final Map
PS:
ThreadLocal是线程内部的存储类,通过它我们可以在指定的线程中存储数据,存储完只能在指定的线程中获取到数据,其他线程就无法获取到该线程的数据。
- 构造函数:
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
// 用于线程间调度
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
// 用于记录event生成索引
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
// 对已经注解过的Method的查找器,会对所设定过 @Subscriber 注解的的方法查找相应的Event
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
// 当调用事件处理函数发生异常是否需要打印Log
logSubscriberExceptions = builder.logSubscriberExceptions;
// 当没有订阅者订阅这个消息的时候是否打印Log
logNoSubscriberMessages = builder.logNoSubscriberMessages;
// 当调用事件处理函数,如果异常,是否需要发送Subscriber这个事件
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
// 当没有事件处理函数时,对事件处理是否需要发送sendNoSubscriberEvent这个标志
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
// 是否需要抛出SubscriberException
throwSubscriberException = builder.throwSubscriberException;
// 与Event有继承关系的类是否都需要发送
eventInheritance = builder.eventInheritance;
// 线程池 Executors.newCachedThreadPool()
executorService = builder.executorService;
}
2)跟着源码进去
public class EventBus {
public static EventBusBuilder builder() {
return new EventBusBuilder();
}
}
public class EventBusBuilder {
/**
* Builds an EventBus based on the current configuration.
* 基于当前配置生成事件总线
*/
public EventBus build() {
return new EventBus(this);
}
}
可以看到这两种方法都是通过EventBusBuilder构造出来的。
- EventBusBuilder:
package org.greenrobot.eventbus;
import android.os.Looper;
import org.greenrobot.eventbus.meta.SubscriberInfoIndex;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Creates EventBus instances with custom parameters and also allows to install a custom default EventBus instance.
* 使用自定义参数创建EventBus实例,并允许安装自定义默认EventBus实例
* Create a new builder using {@link EventBus#builder()}.
*/
public class EventBusBuilder {
// 这个就是我们的线程池了,异步任务,后台任务就要靠它来执行了
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
boolean logSubscriberExceptions = true; //订阅者异常日志
boolean logNoSubscriberMessages = true; //不要订阅者消息日志
boolean sendSubscriberExceptionEvent = true; //是否发送订阅者异常
boolean sendNoSubscriberEvent = true; //是否发送无订阅者异常
boolean throwSubscriberException; // 是否抛出订阅者异常
boolean eventInheritance = true; // 是否继承事件
boolean ignoreGeneratedIndex; // 是否忽略生成的索引
boolean strictMethodVerification; // 是否严格执行方法验证
ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; // 默认线程池
List> skipMethodVerificationForClasses; // 需要跳过执行方法验证的类
List subscriberInfoIndexes; // 订阅者信息索引
Logger logger;
MainThreadSupport mainThreadSupport;
EventBusBuilder() {
}
/**
* Default: true 订阅者异常日志,默认打印
*/
public EventBusBuilder logSubscriberExceptions(boolean logSubscriberExceptions) {
this.logSubscriberExceptions = logSubscriberExceptions;
return this;
}
/**
* Default: true 不要订阅者消息日志
*/
public EventBusBuilder logNoSubscriberMessages(boolean logNoSubscriberMessages) {
this.logNoSubscriberMessages = logNoSubscriberMessages;
return this;
}
/**
* Default: true 是否发送订阅者异常
*/
public EventBusBuilder sendSubscriberExceptionEvent(boolean sendSubscriberExceptionEvent) {
this.sendSubscriberExceptionEvent = sendSubscriberExceptionEvent;
return this;
}
/**
* Default: true 是否发送无订阅者异常
*/
public EventBusBuilder sendNoSubscriberEvent(boolean sendNoSubscriberEvent) {
this.sendNoSubscriberEvent = sendNoSubscriberEvent;
return this;
}
/**
* Fails if an subscriber throws an exception (default: false).
* Tip: Use this with BuildConfig.DEBUG to let the app crash in DEBUG mode (only). This way, you won't miss
* exceptions during development.
* 使用buildconfig.debug可以使应用程序在调试模式下崩溃(仅限)。这样,您就不会错过开发过程中的异常。
*
* 是否抛出订阅者异常 默认为 false,可以在debug情况下设置为 true 进行调试
*/
public EventBusBuilder throwSubscriberException(boolean throwSubscriberException) {
this.throwSubscriberException = throwSubscriberException;
return this;
}
/**
* By default, EventBus considers the event class hierarchy (subscribers to super classes will be notified).
* Switching this feature off will improve posting of events. For simple event classes extending Object directly,
* we measured a speed up of 20% for event posting. For more complex event hierarchies, the speed up should be
* >20%.
* 默认情况下,EventBus考虑事件类层次结构(将通知父类的订户)。
* 关闭此功能将改进事件发布。
* 对于直接扩展对象的简单事件类,我们测量到事件发布的速度提高了20%。对于更复杂的事件层次结构,速度应大于20%
*
* However, keep in mind that event posting usually consumes just a small proportion of CPU time inside an app,
* unless it is posting at high rates, e.g. hundreds/thousands of events per second.
* 但是,请记住,事件发布通常只占用应用程序内部CPU时间的一小部分,除非它以高速率发布,例如每秒数百/数千个事件
*
* 是否继承事件,把这个功能关闭可以提高效率,默认为 true
*/
public EventBusBuilder eventInheritance(boolean eventInheritance) {
this.eventInheritance = eventInheritance;
return this;
}
/**
* Provide a custom thread pool to EventBus used for async and background event delivery. This is an advanced
* setting to that can break things: ensure the given ExecutorService won't get stuck to avoid undefined behavior.
* 为用于异步和后台事件传递的事件总线提供自定义线程池。
* 这是一个高级设置,可以打断一些事件:确保给定的ExecutorService不会被卡住以避免未定义的行为
*/
public EventBusBuilder executorService(ExecutorService executorService) {
this.executorService = executorService;
return this;
}
/**
* Method name verification is done for methods starting with onEvent to avoid typos; using this method you can
* exclude subscriber classes from this check. Also disables checks for method modifiers (public, not static nor
* abstract).
* 方法名验证是对以OnEvent开头的方法进行的,以避免出现错误;使用此方法,可以从该检查中排除订阅服务器类。
* 还禁用对方法修饰符(公共、非静态或抽象)的检查
*/
public EventBusBuilder skipMethodVerificationFor(Class> clazz) {
if (skipMethodVerificationForClasses == null) {
skipMethodVerificationForClasses = new ArrayList<>();
}
skipMethodVerificationForClasses.add(clazz);
return this;
}
/**
* Forces the use of reflection even if there's a generated index (default: false).
* 强制使用反射,即使存在生成的索引(默认值:false)。
* 使用索引可以大大提高效率
*/
public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) {
this.ignoreGeneratedIndex = ignoreGeneratedIndex;
return this;
}
/**
* Enables strict method verification (default: false).
* 启用严格的方法验证(默认值:false)
*/
public EventBusBuilder strictMethodVerification(boolean strictMethodVerification) {
this.strictMethodVerification = strictMethodVerification;
return this;
}
/**
* Adds an index generated by EventBus' annotation preprocessor.
* 添加由EventBus的批注预处理器生成的索引,可以添加多个索引
*/
public EventBusBuilder addIndex(SubscriberInfoIndex index) {
if (subscriberInfoIndexes == null) {
subscriberInfoIndexes = new ArrayList<>();
}
subscriberInfoIndexes.add(index);
return this;
}
/**
* Set a specific log handler for all EventBus logging. 为所有事件总线日志记录设置特定的日志处理程序。
*
* By default all logging is via {@link android.util.Log} but if you want to use EventBus
* outside the Android environment then you will need to provide another log target.
* 默认情况下,所有日志记录都是通过 android.util.log进行的,但如果您想在android环境之外使用eventbus,则需要提供另一个日志目标。
*/
public EventBusBuilder logger(Logger logger) {
this.logger = logger;
return this;
}
Logger getLogger() {
if (logger != null) {
return logger;
} else {
// also check main looper to see if we have "good" Android classes (not Stubs etc.)
return Logger.AndroidLogger.isAndroidLogAvailable() && getAndroidMainLooperOrNull() != null
? new Logger.AndroidLogger("EventBus") :
new Logger.SystemOutLogger();
}
}
MainThreadSupport getMainThreadSupport() {
if (mainThreadSupport != null) {
return mainThreadSupport;
} else if (Logger.AndroidLogger.isAndroidLogAvailable()) {
Object looperOrNull = getAndroidMainLooperOrNull();
return looperOrNull == null ? null :
new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
} else {
return null;
}
}
Object getAndroidMainLooperOrNull() {
try {
return Looper.getMainLooper();
} catch (RuntimeException e) {
// Not really a functional Android (e.g. "Stub!" maven dependencies)
return null;
}
}
/**
* Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be
* done only once before the first usage of the default EventBus.
* 使用此生成器的值安装 eventbus getdefault()返回的默认eventbus。在第一次使用默认事件总线之前只能执行一次
* 所以在 Application 中执行
* @throws EventBusException if there's already a default EventBus instance in place
* 如果已经有了一个默认的eventbus实例,就抛出异常
*/
public EventBus installDefaultEventBus() {
synchronized (EventBus.class) {
if (EventBus.defaultInstance != null) {
throw new EventBusException("Default instance already exists." +
" It may be only set once before it's used the first time to ensure consistent behavior.");
}
EventBus.defaultInstance = build();
return EventBus.defaultInstance;
}
}
/**
* Builds an EventBus based on the current configuration.
* 基于当前配置生成事件总线
*/
public EventBus build() {
return new EventBus(this);
}
}
从上面可以看出通过 EventBusBuilder 这个类可以构建出我们想要的EventBus。
注意点:installDefaultEventBus()方法的调用,使用这个方法生成的 EventBus,在第一次使用默认事件总线之前只能执行一次,所以在 Application 中执行,如果已经有了一个默认的eventbus实例,就抛出异常。
2.注册订阅者
EventBus eventBus = EventBus.builder().build();
eventBus.register(this);
- register方法:
/**
* 注册给定的订阅服务器以接收事件。一旦订户对接收事件不再感兴趣,他们必须调用 unregister(object)。
* 订阅服务器具有必须由 subscribe 注释的事件处理方法。 subscribe注释还允许配置,如 threadMode 和优先级。
*
* 传进来的是订阅者 subscriber
*/
public void register(Object subscriber) {
// 通过反射获取到订阅者的对象
Class> subscriberClass = subscriber.getClass();
// 通过Class对象找到对应的订阅者方法集合
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
// 遍历订阅者方法集合,将订阅者和订阅者放方法想成订阅关系
synchronized (this) {
// 迭代每个 Subscribe 方法,调用 subscribe() 传入 subscriber(订阅者) 和 subscriberMethod(订阅方法) 完成订阅,
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
- private final SubscriberMethodFinder subscriberMethodFinder; // 对已经注解过的Method的查找器。
- findSubscriberMethods方法:
// 订阅方法的缓存,key为订阅者对象,value为订阅者对象所有的订阅方法是一个List集合
private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>();
/**
* 订阅方法查找
* @param subscriberClass 订阅者对象
* @return 返回订阅者 所有的订阅方法 是一个List集合
*/
List findSubscriberMethods(Class> subscriberClass) {
// 首先在 METHOD_CACHE 中查找该 Event 对应的订阅者集合是否已经存在,如果有直接返回
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
// 根据订阅者类 subscriberClass 查找相应的订阅方法
if (ignoreGeneratedIndex) { // 是否忽略生成 index 默认为 false,当为 true 时,表示以反射的方式获取订阅者中的订阅方法
subscriberMethods = findUsingReflection(subscriberClass); // 通过反射获取
} else {
// 通过 SubscriberIndex 方式获取
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); // 把订阅方法集合 List 存到缓存中
return subscriberMethods;
}
}
- findUsingReflection() 通过反射获取订阅方法集合 *** start ***
private List findUsingReflection(Class> subscriberClass) {
// 创建并初始化 FindState 对象
FindState findState = prepareFindState();
// findState 与 subscriberClass 关联
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 使用反射的方式获取单个类的订阅方法
findUsingReflectionInSingleClass(findState);
// 使 findState.clazz 指向父类的 Class,继续获取
findState.moveToSuperclass();
}
// 返回订阅者及其父类的订阅方法 List,并释放资源
return getMethodsAndRelease(findState);
}
- prepareFindState()方法:
class SubscriberMethodFinder {
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
}
// 通过 prepareFindState 获取到 FindState 对象
private FindState prepareFindState() {
// 找到 FIND_STATE_POOL 对象池
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
// 当找到了对应的FindState
FindState state = FIND_STATE_POOL[i];
if (state != null) { // FindState 非空表示已经找到
FIND_STATE_POOL[i] = null; // 清空找到的这个FindState,为了下一次能接着复用这个FIND_STATE_POOL池
return state; // 返回该 FindState
}
}
}
// 如果依然没找到,则创建一个新的 FindState
return new FindState();
}
- FindState这是EventBus的一个静态内部类:
// FindState 封装了所有的订阅者和订阅方法的集合
static class FindState {
// 保存所有订阅方法
final List subscriberMethods = new ArrayList<>();
// 事件类型为Key,订阅方法为Value
final Map anyMethodByEventType = new HashMap<>();
// 订阅方法为Key,订阅者的Class对象为Value
final Map subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class> subscriberClass;
Class> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
// findState 与 subscriberClass 关联
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;
}
/**
* EventBus 不仅仅获取当前类的订阅方法,还会获取它所有父类的订阅方法。
*
* 在 EventBus 中,一个订阅者包括这个订阅者的所有父类和子类,不会有多个方法相同的去接收同一个事件.
* 但是有可能出现这样一种情况,子类去订阅了该事件,父类也去订阅了该事件。
* 当出现这种情况,EventBus 如何判断?通过调用 checkAddWithMethodSignature() 方法,根据方法签名来检查
*/
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.
// put()方法执行之后,返回的是之前put的值
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();
// put方法返回的是put之前的对象
Class> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
// 如果methodClassOld不存在或者是methodClassOld的父类的话,则表明是它的父类,直接返回true。
// 否则,就表明在它的子类中也找到了相应的订阅,执行的 put 操作是一个 revert 操作,put 进去的是 methodClassOld,而不是 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
// 这里是一个revert操作,所以如果找到了它的子类也订阅了该方法,则不允许父类和子类都同时订阅该事件,put 的是之前的那个 methodClassOld,就是将以前的那个 methodClassOld 存入 HashMap 去覆盖相同的订阅者。
// 不允许出现一个订阅者有多个相同方法订阅同一个事件
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
// 使 findState.clazz 指向父类的 Class,继续获取
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;
}
}
}
}
- findUsingReflectionInSingleClass方法:
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 的方法
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
// 获取订阅方法的所有参数
Class>[] parameterTypes = method.getParameterTypes();
// 订阅方法只能有一个参数,否则忽略
if (parameterTypes.length == 1) {
// 获取有 Subscribe 的注解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
// 获取第一个参数
Class> eventType = parameterTypes[0];
// 检查 eventType 决定是否订阅,通常订阅者不能有多个 eventType 相同的订阅方法
if (findState.checkAdd(method, eventType)) {
// 获取线程模式
ThreadMode threadMode = subscribeAnnotation.threadMode();
// 添加订阅方法进 List
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");
}
}
}
- getMethodsAndRelease方法: 返回订阅者及其父类的订阅方法 List,并释放资源
// 保存所有订阅方法
final List subscriberMethods = new ArrayList<>();
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
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;
}
上面这一堆方法都是讲的从反射获取订阅者的方法。 end
下面这个方法表示从索引获取:
- 通过 SubscriberIndex 方式获取
findUsingInfo方法:
private List findUsingInfo(Class> subscriberClass) {
// 通过 prepareFindState 获取到 FindState(保存找到的注解过的方法的状态)
FindState findState = prepareFindState();
// findState 与 subscriberClass 关联
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 获取订阅者信息
// 通过 SubscriberIndex 获取 findState.clazz 对应的 SubscriberInfo
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
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
// 使用反射的方式获取单个类的订阅方法
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
这个方法里面的涉及到的方法在上面讲发射的时候都有了,这里就不重复了。引入一个新的接口:
- SubscriberInfo:
/**
* Base class for generated index classes created by annotation processing.
* 由批注处理创建的已生成索引类的基类
*/
public interface SubscriberInfo {
Class> getSubscriberClass();
SubscriberMethod[] getSubscriberMethods();
SubscriberInfo getSuperSubscriberInfo();
boolean shouldCheckSuperclass();
}
- AbstractSubscriberInfo是SubscriberInfo 实现的抽象类
/**
* Base class for generated subscriber meta info classes created by annotation processing.
* 由批注处理创建的已生成订阅服务器元信息类的基类
*/
public abstract class AbstractSubscriberInfo implements SubscriberInfo {
private final Class subscriberClass;
private final Class extends SubscriberInfo> superSubscriberInfoClass;
private final boolean shouldCheckSuperclass;
protected AbstractSubscriberInfo(Class subscriberClass, Class extends SubscriberInfo> superSubscriberInfoClass,
boolean shouldCheckSuperclass) {
this.subscriberClass = subscriberClass;
this.superSubscriberInfoClass = superSubscriberInfoClass;
this.shouldCheckSuperclass = shouldCheckSuperclass;
}
@Override
public Class getSubscriberClass() {
return subscriberClass;
}
@Override
public SubscriberInfo getSuperSubscriberInfo() {
if (superSubscriberInfoClass == null) {
return null;
}
try {
return superSubscriberInfoClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean shouldCheckSuperclass() {
return shouldCheckSuperclass;
}
protected SubscriberMethod createSubscriberMethod(String methodName, Class> eventType) {
return createSubscriberMethod(methodName, eventType, ThreadMode.POSTING, 0, false);
}
protected SubscriberMethod createSubscriberMethod(String methodName, Class> eventType, ThreadMode threadMode) {
return createSubscriberMethod(methodName, eventType, threadMode, 0, false);
}
protected SubscriberMethod createSubscriberMethod(String methodName, Class> eventType, ThreadMode threadMode,
int priority, boolean sticky) {
try {
Method method = subscriberClass.getDeclaredMethod(methodName, eventType);
return new SubscriberMethod(method, eventType, threadMode, priority, sticky);
} catch (NoSuchMethodException e) {
throw new EventBusException("Could not find subscriber method in " + subscriberClass +
". Maybe a missing ProGuard rule?", e);
}
}
}
- SimpleSubscriberInfo最终继承上面的抽象类
/**
* Uses {@link SubscriberMethodInfo} objects to create {@link SubscriberMethod} objects on demand.
* 使用 SubscriberMethodInfo 对象根据需要创建 SubscriberMethod 对象。
*/
public class SimpleSubscriberInfo extends AbstractSubscriberInfo {
private final SubscriberMethodInfo[] methodInfos;
public SimpleSubscriberInfo(Class subscriberClass, boolean shouldCheckSuperclass, SubscriberMethodInfo[] methodInfos) {
super(subscriberClass, null, shouldCheckSuperclass);
this.methodInfos = methodInfos;
}
@Override
public synchronized SubscriberMethod[] getSubscriberMethods() {
int length = methodInfos.length;
SubscriberMethod[] methods = new SubscriberMethod[length];
for (int i = 0; i < length; i++) {
SubscriberMethodInfo info = methodInfos[i];
methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode,
info.priority, info.sticky);
}
return methods;
}
}
- 最后就是要创建出的 SubscriberMethod 对象
/**
* Used internally by EventBus and generated subscriber indexes.
*
* 封装了EventBus中的参数,就是一个EventBus订阅方法包装类
*/
public class SubscriberMethod {
final Method method;
final ThreadMode threadMode;
final Class> eventType;
final int priority;
final boolean sticky;
/**
* Used for efficient comparison
*/
String methodString;
public SubscriberMethod(Method method, Class> eventType, ThreadMode threadMode, int priority, boolean sticky) {
this.method = method;
this.threadMode = threadMode;
this.eventType = eventType;
this.priority = priority;
this.sticky = sticky;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (other instanceof SubscriberMethod) {
checkMethodString();
SubscriberMethod otherSubscriberMethod = (SubscriberMethod) other;
otherSubscriberMethod.checkMethodString();
// Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
return methodString.equals(otherSubscriberMethod.methodString);
} else {
return false;
}
}
private synchronized void checkMethodString() {
if (methodString == null) {
// Method.toString has more overhead, just take relevant parts of the method
StringBuilder builder = new StringBuilder(64);
builder.append(method.getDeclaringClass().getName());
builder.append('#').append(method.getName());
builder.append('(').append(eventType.getName());
methodString = builder.toString();
}
}
@Override
public int hashCode() {
return method.hashCode();
}
}
到这里索引也分析完了,索引的具体使用:https://www.jianshu.com/p/1e624bf9144d
接下来注册的关键性一步:将订阅者和订阅者放方法形成订阅关系
subscribe方法:
// Must be called in synchronized block 必须组同步块中调用
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.eventType;
// 创建 Subscription 封装订阅者和订阅方法信息
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// 可并发读写的 ArrayList(CopyOnWriteArrayList)),key为 EventType,value为 Subscriptions
// 根据事件类型从 subscriptionsByEventType 这个 Map 中获取 Subscription 集合
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
// 如果为 null,表示还没有(注册)订阅过,创建并 put 进 Map
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
// 若subscriptions中已经包含newSubscription,表示该newSubscription已经被订阅过,抛出异常
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
// 按照优先级插入subscriptions
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;
}
}
// key为订阅者,value为eventType,用来存放订阅者中的事件类型
List> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
// 将EventType放入subscribedEvents的集合中
subscribedEvents.add(eventType);
//判断是否为Sticky事件
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).
// 获取到所有Sticky事件的Set集合
Set, Object>> entries = stickyEvents.entrySet();
//遍历所有Sticky事件
for (Map.Entry, Object> entry : entries) {
Class> candidateEventType = entry.getKey();
//判断当前事件类型是否为黏性事件或者其子类
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
// 执行设置了 sticky 模式的订阅方法
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
- 这里涉及到一个类Subscription:
// 封装订阅者和订阅方法信息
final class Subscription {
final Object subscriber; // 订阅者对象
final SubscriberMethod subscriberMethod; // 订阅的方法
}
- 检查有没有post粘性的事件
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, isMainThread());
}
}
- postToSubscription方法: 这里调用主要是为了检查没有注册之前是否发送了黏性事件
/**
* 订阅者五种线程模式的特点对应的就是以上代码,简单来讲就是订阅者指定了在哪个线程订阅事件,无论发布者在哪个线程,它都会将事件发布到订阅者指定的线程
* @param subscription
* @param event
* @param isMainThread
*/
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
// 订阅线程跟随发布线程,EventBus 默认的订阅方式
case POSTING:
invokeSubscriber(subscription, event); // 订阅线程和发布线程相同,直接订阅
break;
// 订阅线程为主线程
case MAIN:
if (isMainThread) { // 如果 post是在 UI 线程,直接调用 invokeSubscriber
invokeSubscriber(subscription, event);
} else {
// 如果不在 UI 线程,用 mainThreadPoster 进行调度,即上文讲述的 HandlerPoster 的 Handler 异步处理,将订阅线程切换到主线程订阅
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:
// 如果在 UI 线程,则将 subscription 添加到后台线程的线程池
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
// 不在UI线程,直接分发
invokeSubscriber(subscription, event);
}
break;
// 订阅线程为异步线程
case ASYNC:
// 使用线程池线程订阅
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
到这里注册流程就分析完了,下面贴上一张整体流程图:
3.书写接收订阅事件的方法
@Subscribe(threadMode = ThreadMode.POSTING,sticky = false,priority = 4)
public void onEventThread(EventCenter eventCenter){
switch (eventCenter.getEventType()) {
case EventType.ONE:
Log.e("MainActivity", eventCenter.getEventType());
break;
default:
break;
}
// EventBus.getDefault().cancelEventDelivery(eventCenter);
}
- 这里主要涉及到注解及黏性事件。
注解:
@Documented // 命名为 java doc 文档
@Retention(RetentionPolicy.RUNTIME) // 指定在运行时有效,即在运行时能保持这个 Subscribe
@Target({ElementType.METHOD}) // 指定类型为 METHOD,表名用来描述方法
public @interface Subscribe {
// 指定线程模式,可以指定在 Subscribe 中接收的 Event 所处的线程
ThreadMode threadMode() default ThreadMode.POSTING; // 订阅线程的模式,默认从哪个线程发送,就从哪个线程订阅
/**
* If true, delivers the most recent sticky event (posted with
* {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
* 粘性事件是事件消费者在事件发布之后才注册,依然能接收到该事件的特殊类型。
*/
boolean sticky() default false;
/** Subscriber priority to influence the order of event delivery.
* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
* delivery among subscribers with different {@link ThreadMode}s!
* 数值越高优先级越大,越先接收事件
* */
int priority() default 0;
}
总结:
- 粘性事件是事件消费者在事件发布之后才注册,依然能接收到该事件的特殊类型
- 任何时候在任何一个订阅了该事件的订阅者中的任何地方,都可以通 EventBus.getDefault().getStickyEvent(MyEvent.class)来取得该类型事件的最后一次缓存。
- 优先级priority数值越高优先级越大,越先接收事件
线程模式ThreadMode
/**
* Each subscriber method has a thread mode, which determines in which thread the method is to be called by EventBus.
* EventBus takes care of threading independently from the posting thread.
*
* 每个订阅服务器方法都有一个线程模式,该模式决定EventBus在哪个线程中调用该方法。EventBus独立于发布线程来处理线程。
*
* @see EventBus#register(Object)
* @author Markus
*/
public enum ThreadMode {
/**
* Subscriber will be called directly in the same thread, which is posting the event. This is the default. Event delivery
* implies the least overhead because it avoids thread switching completely. Thus this is the recommended mode for
* simple tasks that are known to complete in a very short time without requiring the main thread. Event handlers
* using this mode must return quickly to avoid blocking the posting thread, which may be the main thread.
*
* 订阅服务器将直接在发布事件的同一线程中调用。这是默认设置。事件传递意味着开销最小,因为它完全避免了线程切换。
* 因此,对于已知在非常短的时间内完成而不需要主线程的简单任务,建议使用这种模式。
* 使用此模式的事件处理程序必须快速返回,以避免阻塞可能是主线程的发布线程。
*/
POSTING, // EventBus 默认的线程模式 就是订阅的线程和发送事件的线程为同一线程
/**
* On Android, subscriber will be called in Android's main thread (UI thread). If the posting thread is
* the main thread, subscriber methods will be called directly, blocking the posting thread. Otherwise the event
* is queued for delivery (non-blocking). Subscribers using this mode must return quickly to avoid blocking the main thread.
* If not on Android, behaves the same as {@link #POSTING}.
*
*
* 在Android上,用户将在Android的主线程(UI线程)中被调用。
* 如果发布线程是主线程,则将直接调用订阅方法,从而阻塞发布线程。否则,事件将排队等待传递(非阻塞)。
* 使用此模式的订阅必须快速返回,以避免阻塞主线程。如果不在Android上,其行为与 POSTING 发布相同。
* 因为安卓主线程阻塞会发生 ANR 异常
*/
MAIN, // 主线程
/**
* On Android, subscriber will be called in Android's main thread (UI thread). Different from {@link #MAIN},
* the event will always be queued for delivery. This ensures that the post call is non-blocking.
*
* 在Android上,用户将在Android的主线程(UI线程)中被调用。与 MAIN 不同,事件将始终排队等待传递。这样可以确保后调用不阻塞
*/
MAIN_ORDERED, // 主线程
/**
* On Android, subscriber will be called in a background thread. If posting thread is not the main thread, subscriber methods
* will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single
* background thread, that will deliver all its events sequentially. Subscribers using this mode should try to
* return quickly to avoid blocking the background thread. If not on Android, always uses a background thread.
*
* 在Android上,订阅将在后台线程中被调用。如果发布线程不是主线程,则将直接在发布线程中调用订阅方法。
* 如果发布线程是主线程,那么 eventBus 使用单个后台线程,该线程将按顺序传递其所有事件。
* 使用此模式的订阅应尝试快速返回,以避免阻塞后台线程。如果不在Android上,则始终使用后台线程。
*
*/
BACKGROUND, // 后台线程
/**
* Subscriber will be called in a separate thread. This is always independent from the posting thread and the
* main thread. Posting events never wait for subscriber methods using this mode. Subscriber methods should
* use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number
* of long running asynchronous subscriber methods at the same time to limit the number of concurrent threads. EventBus
* uses a thread pool to efficiently reuse threads from completed asynchronous subscriber notifications.
*
* 将在单独的线程中调用订阅服务器。这始终独立于发布线程和主线程。
* 发布事件从不等待使用此模式的订阅方法。
* 如果订阅服务器方法的执行可能需要一些时间,例如用于网络访问,则应使用此模式。
* 避免同时触发大量长时间运行的异步订阅服务器方法,以限制并发线程的数量。
* EventBus使用线程池来有效地重用已完成的异步订阅服务器通知中的线程。
*
*/
ASYNC // 异步线程
}
4.发送事件给订阅者
// 发送黏性事件
EventBus.getDefault().postSticky(new EventCenter<>(EventType.ONE));
// 发送普通事件
EventBus.getDefault().post(new EventCenter<>(EventType.ONE));
- postSticky方法:
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately 如果订阅者希望立即删除,则应在放入后发布
post(event);
}
- post方法:
/**
* Posts the given event to the event bus.
* 将给定事件发布到事件总线
*/
public void post(Object event) {
// 获取当前线程的 posting 状态
PostingThreadState postingState = currentPostingThreadState.get();
// 获取当前事件队列
List
- 发送事件的线程封装类 PostingThreadState
/**
* For ThreadLocal, much faster to set (and get multiple values).
*
* 发送事件的线程封装类
*/
final static class PostingThreadState {
final List
- postSingleEvent 发送方法:
/**
* 发送事件
*
* EventBus 用 ThreadLocal 存储每个线程的 PostingThreadState,一个存储了事件发布状态的类,
* 当 post 一个事件时,添加到事件队列末尾,等待前面的事件发布完毕后再拿出来发布,
* 这里看事件发布的关键代码postSingleEvent()
*/
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) { // 处理继承事件
List> 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);
}
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)); // 如果没有人和订阅者订阅发送 NoSubscriberEvent
}
}
}
- lookupAllEventTypes方法:
/**
* Looks up all Class objects including super classes and interfaces. Should also work for interfaces.
* 看看涉及到lookupAllEventTypes,就是查找到发生事件的所有相关类(父类)
*/
private static List> lookupAllEventTypes(Class> eventClass) {
synchronized (eventTypesCache) {
List> eventTypes = eventTypesCache.get(eventClass);
if (eventTypes == null) {
eventTypes = new ArrayList<>();
Class> clazz = eventClass;
while (clazz != null) {
eventTypes.add(clazz);
addInterfaces(eventTypes, clazz.getInterfaces());
clazz = clazz.getSuperclass();
}
eventTypesCache.put(eventClass, eventTypes);
}
return eventTypes;
}
}
/**
* Recurses through super interfaces. 遍历父类接口
*/
static void addInterfaces(List> eventTypes, Class>[] interfaces) {
for (Class> interfaceClass : interfaces) {
if (!eventTypes.contains(interfaceClass)) {
eventTypes.add(interfaceClass);
addInterfaces(eventTypes, interfaceClass.getInterfaces()); // 递归
}
}
}
- postSingleEventForEventType方法:
// 进一步深入的发送事件函数:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class> eventClass) {
CopyOnWriteArrayList subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass); // 查找是否存在处理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;
}
最终走了这个方法postToSubscription()进行事件发送
/**
* 订阅者五种线程模式的特点对应的就是以上代码,简单来讲就是订阅者指定了在哪个线程订阅事件,无论发布者在哪个线程,它都会将事件发布到订阅者指定的线程
* @param subscription
* @param event
* @param isMainThread
*/
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
// 订阅线程跟随发布线程,EventBus 默认的订阅方式
case POSTING:
invokeSubscriber(subscription, event); // 订阅线程和发布线程相同,直接订阅
break;
// 订阅线程为主线程
case MAIN:
if (isMainThread) { // 如果 post是在 UI 线程,直接调用 invokeSubscriber
invokeSubscriber(subscription, event);
} else {
// 如果不在 UI 线程,用 mainThreadPoster 进行调度,即上文讲述的 HandlerPoster 的 Handler 异步处理,将订阅线程切换到主线程订阅
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:
// 如果在 UI 线程,则将 subscription 添加到后台线程的线程池
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
// 不在UI线程,直接分发
invokeSubscriber(subscription, event);
}
break;
// 订阅线程为异步线程
case ASYNC:
// 使用线程池线程订阅
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
到这里事件发送也分析完了,老规矩附上流程图:
由于篇幅所限,剩下的内容传送门:https://www.jianshu.com/p/f61b8e7da6b4