基于EventBus 3.1.1
主要参考:EventBus 3.0 源码分析
在其基础上添加了些个人理解,建议直接看参考原文
注册订阅者
EventBus.getDefault().register(this)
-
获取默认的 EventBus 实例
在程序中创建多个EventBus 的实例,每个EventBus可看做一个管道,管道间相互独立
getDefault()
就是获取一个全局默认的管道, 因为多数场景下只需要用一个 EventBus 实例即可(尤其事件的收发需要同一个实例,所以提供了默认的实例的获取方法)EventBusBuilder 设置的是 EventBus 的配置信息
,即EventBus可能有几个属性在不同的应用场景下需要有不同的值;同时EventBus也有都是固定值的属性,这些直接在EventBus初始化时赋值或初始化即可- EventBus 的几个成员变量
a.subscriptionsByEventType
: Map<Class<?>, CopyOnWriteArrayList>
b.typesBySubscriber
: Map<Object, List<Class<?>>>
c.stickyEvents
: Map<Class<?>, Object>
public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; } public EventBus() { // private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder(); this(DEFAULT_BUILDER); } // 通过一个 EventBusBuilder 将配置解耦出去, 这些配置可能 不同的 EventBus 实例 需要有不同的配置 // 而对于每个EventBus 都需要有的相同的属性 在 EventBus 初始化时 自身设置初值 EventBus(EventBusBuilder builder) { logger = builder.getLogger(); // private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; // 当前 EventBus 内 以事件类型为键值, 以订阅了该事件的 所有订阅者信息集合为值 的 map subscriptionsByEventType = new HashMap<>(); // private final Map<Object, List<Class<?>>> typesBySubscriber; // 以订阅者对象为键,以该订阅者订阅了的事件类型的集合为值,用于 在unregister()被调用时,将该订阅者从 EventBus 的订阅者中移除 typesBySubscriber = new HashMap<>(); // private final Map<Class<?>, Object> stickyEvents; // 以事件类为键,以该事件类的一个对象为 值的 map // 用于存储每个订阅事件类的被发出的最新的一个粘性事件对象 stickyEvents = new ConcurrentHashMap<>(); mainThreadSupport = builder.getMainThreadSupport(); mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; // 负责 查找 订阅者的响应方法 subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; sendNoSubscriberEvent = builder.sendNoSubscriberEvent; throwSubscriberException = builder.throwSubscriberException; eventInheritance = builder.eventInheritance; executorService = builder.executorService; }
-
注册订阅者
注册订阅者,就是
注册订阅者的订阅方法
, 当有一个事件发布到当前管道中时(即 EventBus # post()发布了个事件),最终需要的是 订阅者的订阅方法们被调用,所以 是注册的订阅方法,注册订阅方法的同时也需要注册该方法的调用者即订阅者本身- 注册订阅者,首先找到这个订阅者的所有订阅方法(将来在对应的订阅事件发出时,做出响应)
a. 根据订阅者对象获取订阅者的类对象
b.List<SubscriberMethod> subscribeMethodFinder.findSubscribeMethods()
找到这个订阅者的所有的 订阅方法信息;
c. 依次注册当前订阅者的 所有订阅方法 - findSubscribeMethods(Class subscriberClass) 的内部实现:
a. subscriberMethodFinder 实例在 EventBus 对象创建时被实例化,其生命周期与EventBus一致, 该订阅方法寻找类内部有一个Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE
,故它的生命周期也与EventBus一致
,它作为一个备忘录,当寻找某个订阅者类的订阅方法时先在 map 中寻找,有直接返回,没有再找,找到后先存储在 map 中,再返回
b. EventBus 3.0 提供一个注解处理器,在编译阶段通过读取解析 所有 订阅者类 中的 @Subscribe 注解信息,存储在一个 java类中(实际用 Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX 存储),等运行阶段就不用再通过反射获取订阅方法信息
c. SubscriberInfo 是一个接口 声明了 订阅者订阅方法集合的获取方法
d. ignoreGeneratedIndex 即为 EventBusBuilder 传入的配置信息,默认为false, 表示使用 b 中注解处理器解析的 订阅者的方法信息 而不是运行时通过反射获取订阅方法
e. findUsingInfo() 通过 查找注解处理器生成的 map 获取 当前订阅者的 订阅方法集合
f. findUsingReflection()运行时通过反射获得
先跳过 - eventInheritance 可以父类引用指向子类对象, 即 发送了一个子类对象, 订阅方法订阅的是父类类型,那么也可以响应,实际收到的是子类对象,也是使用的子类对象的方法 或 属性
public void register(Object subscriber) { // 获取订阅者类的 类对象 Class<?> subscriberClass = subscriber.getClass(); List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } } // SubscribeMethod 的属性包括: // Method 方法对象 // ThreadMode 通过 Subscribe 注解指定的属性 执行订阅方法的线程 // eventType 响应的事件(接收的管道中的事件) // priority 响应方法执行的优先级 (一个事件发出后 统一管道下 优先级高的先执行 (是否为顺序??)) // sticky 本方法是否响应粘性事件 // methodString List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { // private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>(); // 之前找过这个订阅者类的 订阅方法 List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } // EventBusBuilder 配置的属性, 是否由忽略EventBus提供的注解处理器 根据 订阅者类 的注解 在编译期生成的 订阅者类 (默认为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 { METHOD_CACHE.put(subscriberClass, subscriberMethods); return subscriberMethods; } } /** * This class is generated by EventBus, do not edit. * 注解处理器 读取 所有订阅者的 注解信息 生成的 类 */ public class MyEventBusIndex implements SubscriberInfoIndex { private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX; static { SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>(); putIndex(new SimpleSubscriberInfo(org.greenrobot.eventbusperf.testsubject.PerfTestEventBus.SubscriberClassEventBusAsync.class, // true, new SubscriberMethodInfo[]{ // 实例包括: methodName, threadMode, priority, sticky, eventType new SubscriberMethodInfo("onEventAsync", TestEvent.class, ThreadMode.ASYNC), })); // SimpleSubscriberInfo(Class subscriberClass, boolean shouldCheckSuperclass, SubscriberMethodInfo[] methodInfos) // 订阅者类类对象 是否要检查父类 订阅者的订阅方法集合 putIndex(new SimpleSubscriberInfo(TestRunnerActivity.class, true, new SubscriberMethodInfo[]{ new SubscriberMethodInfo("onEventMainThread", TestFinishedEvent.class, ThreadMode.MAIN), })); } private static void putIndex(SubscriberInfo info) { SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info); } @Override public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) { SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass); if (info != null) { return info; } else { return null; } } }
方法注册过程
// Must be called in synchronized block private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { // 当前方法订阅事件的类型 Class<?> eventType = subscriberMethod.eventType; // 包裹订阅者 和 当前订阅方法 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); // 根据类型找 这个EventBus管道中 订阅了当前类型的 订阅包裹(包订阅者和订阅方法)的集合,没有就新建,有就取出来 看当前订阅者是不是已经注册了 是就抛异常 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); } } // 将当前包裹 放到 当前 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) { // 当前方法响应粘性事件 // 通过 EventBusBuilder 配置的 默认为true // 即 当前响应 A 类对象 现在收到了它的子类对象 那么 也响应 // 其实就是 父类引用指向子类对象, 实际传入的是子类对象, 多态的体现 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(); // 父类.class.isAssignableFrom(子类.class) // 即 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, isMainThread()); } }
- 注册订阅者,首先找到这个订阅者的所有订阅方法(将来在对应的订阅事件发出时,做出响应)
发送事件
EventBus.getDefault().post(new SecondToFirstEvent("2发送给1的事件"));
将事件发送到 EventBus 这个管子中
post(Object event)
每个线程中有一个 PostingThreadState 记录当前线程 事件的投递状态
a. 这个 PostingThreadState 内部靠一个 ArrayList 存储要发到 EventBus 中的事件
b. 每次投递都把 ArrayList 中的事件都投递出去
c. post() 中 事件先被加入到这个 ArrayList中postSingleEvent(Object event, PostingThreadState postingState)
a. 判断是否能找到该事件的订阅者, 不能找到 看是否需要发 NoSubscriberEventpostSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass)
a. 根据类型 在 subscriptionsByEventType 中 找到订阅类型为本事件的 所有订阅者包裹(订阅者及方法)postToSubscription(subscription, event, postingState.isMainThread)
a. 真正的执行
/** Posts the given event to the event bus. */
public void post(Object event) {
// ThreadLocal<PostingThreadState> currentPostingThreadState
// 线程内部存储的 postingState
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;
}
}
}
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<>();
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false; // 是否找到了当前事件的响应方法
if (eventInheritance) { // 是否让接收 当前事件父类的 订阅方法响应本事件
// 获取 eventClass 的所有父类以及接口
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 {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) { // 没有订阅者响应本事件
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
// EventBusBuilder配置的
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.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;
}
执行事件
根据订阅方法的定义的 线程模式 选用不同的执行线程
- POSTING
响应方法执行线程与发布事件的线程一致,若执行线程为主线程 则不能进行耗时的操作- MAIN
- BACKGROUND 适用于轻微耗时,且不会操作不会过于频繁 (相当于只有一个线程在执行这类事件)
- ASYNC 适用于长耗时操作 如 网络访问, 有一个事件 就线程池中取一个线程执行它
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 {
// HandlerPoster 继承自Handler,它在主线程中创建, 此方法调用时,将 订阅信息 和 事件入队,并给这个 Handler 发送一个消息
// 接着 该 Handler 的 handleMessage() 就会被调用, 在其中 eventBus.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, 在run() 中将队列中的 逐个 包裹取出,逐个执行
// 本方法执行时,将 包裹 入队, 用 ExecutorService 执行这个 Runnable
// 队列中的包裹 即 响应本事件的订阅方法们 是 按照顺序依次执行的, 一个执行完另一个才能执行,
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
// 也是实现 Runnable 接口, 调用本方法 先包裹入队,然后用线程池执行本 Runnable, run() 方法中 会取出刚刚入队的包裹 执行 eventBus.invokeSubscriber()
// 分发一个响应的订阅事件就起一个线程执行它 是异步的 并发的
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
// 直接通过反射调用
void invokeSubscriber(Subscription subscription, Object event) {
try { // 找到方法对象 传入 真正的调用者 及 参数 到 invoke() 中
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.getDefault().unregister(this);
- 找到该订阅者订阅的所有的事件类型
- 根据找到事件类型 找到 该事件类型的所有的订阅者, 从这所有的订阅者中 将当前订阅者移除
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
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);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
引用:
业内对EventBus的主要争论点是在于EventBus使用反射会出现性能问题,关于反射的性能问题可以参考这篇文章,
实际上在EventBus里我们可以看到不仅可以使用注解处理器预处理获取订阅信息,EventBus也会将订阅者的方法缓存到METHOD_CACHE里避免重复查找,所以只有在最后
invoke()方法的时候会比直接调用多出一些性能损耗,但是这些对于我们移动端来说是完全可以忽略的.所以盲目的说因为性能问题而觉得EventBus不值得使用显然是不
负责任的
来源:CSDN
作者:yangdamengde
链接:https://blog.csdn.net/weixin_42128119/article/details/104511335