360网站免费推广怎么做ueditor wordpress4.5
- 作者: 五速梦信息网
- 时间: 2026年03月17日 17:14
当前位置: 首页 > news >正文
360网站免费推广怎么做,ueditor wordpress4.5,网页界面设计的网络系统有哪些,邯郸百度审核文章目录 前言一、EventBus 简介EventBus 三要素EventBus 线程模型 二、EventBus 使用1.添加依赖2.EventBus 基本使用2.1 定义事件类2.2 注册 EventBus2.3 EventBus 发起通知 三、EventBus 源码详解1.Subscribe 注解2.注册事件订阅方法2.1 EventBus 实例2.2 EventBus 注册2.2.1… 文章目录 前言一、EventBus 简介EventBus 三要素EventBus 线程模型 二、EventBus 使用1.添加依赖2.EventBus 基本使用2.1 定义事件类2.2 注册 EventBus2.3 EventBus 发起通知 三、EventBus 源码详解1.Subscribe 注解2.注册事件订阅方法2.1 EventBus 实例2.2 EventBus 注册2.2.1 SubscriberMethodFinder#findSubscriberMethods()2.2.1.1 SubscriberMethodFinder#findUsingInfo()2.2.1.2 SubscriberMethodFinder#findUsingReflectionInSingleClass()2.2.1.3 SubscriberMethodFinder#FindState#checkAdd() 2.2.2 EventBus#subscribe() 3.EventBus 取消注册3.1 EventBus#unregister()3.2 EventBus#unsubscribeByEventType() 4.EventBus 发布、处理事件4.1 EventBus#post()4.2 EventBus#postSingleEvent()4.3 EventBus#postSingleEventForEventType()4.4 EventBus#postToSubscription()4.4.1 EventBus#invokeSubscriber()4.4.2 HandlerPoster#enqueue()4.4.3 EventBus#invokeSubscriber()4.4.4 BackgroundPoster#enqueue()4.4.5 AsyncPoster#enqueue() EventBus 发布事件(包括粘性事件)及处理流程 5.EventBus 粘性事件5.1 EventBus#postSticky()5.2 EventBus#subscribe()5.3 EventBus#checkPostStickyEventToSubscription() 6.EventBus 之 Subscriber Index6.1 EventBusIndex6.2 EventBusBuilder#addIndex()6.2 EventBusBuilder#installDefaultEventBus()6.3 SubscriberMethodFinder#findUsingInfo()6.3.1 SubscriberMethodFinder#getSubscriberInfo()6.3.2 SimpleSubscriberInfo#getSubscriberMethods() 小结 总结参考 前言
在 Android 项目开发的时候经常会遇到组件与组件之间、组件与后台线程之间的通信 比如子线程中进行数据请求请求数据成功后通过 Handler、RxJava 等来通知 UI 主线程进行更新操作两个 Fragment 之间可以通过 Listener 进行通信简单的通信通过上述的技术手段也是可以满足需求的但随着项目的不断迭代更新程序越来越庞大时就会要写很多的代码从而导致代码严重的耦合问题。为了优化该问题EventBus 事件总线应运而生。 一、EventBus 简介
EventBus 事件总线是一款由 GreenRobot 开源的在 Android 开发中使用的发布/订阅事件总线框架基于观察者模式将事件的接收者和发送者分开解耦。用来替代广播 BroadCastReceiver、startActivityForResult、Handler 和异步回调等来实现各组件间、组件与后台线程间的通信。
EventBus 优点
简化组件之间的通讯方式对通信双方进行解藕通过 ThreadMode 灵活切换工作线程速度快、性能好、库比较小、不占内存
首先看一下官方给出的 EventBus 原理图 Publisher 使用 post() 函数发出一个 Event 事件Subscriber 在 onEvent() 函数中接收事件、进行后续的处理。
EventBus 三要素
使用 EventBus 时的三个重要参与者Event、Publisher、Subscriber。
Event事件它可以是任意类型Publisher事件的发布者可以在任意线程里发布事件一般情况下使用 EventBus.getDefault() 方法就可以得到一个 EventBus 对象然后再调用其 post(Object) 方法即可Subscriber事件订阅者在 EventBus3.0 之前我们必须定义以 onEvent 开头的那几个方法分别是onEvent、onEventMainThread、onEventBackgroundThread 和 onEventAsync而在 3.0 之后事件处理的方法名可以随意取不过需要加上注解 subscribe()并且要指定线程模型默认是 POSTING。
EventBus 线程模型
ThreadMode 线程模式通过 threadMode 设置 onReceiveMsg() 方法将在哪个线程环境下被调用。其中 threadMode 属性有如下几个可选值
ThreadMode.POSTING默认的线程模式订阅者的订阅方法将在发布事件的同一线程中被调用避免了线程切换效率高但是可能发布事件的线程是主线程所以需要避免在订阅方法中处理耗时操作ThreadMode.MAIN订阅者的订阅方法将在 UI 线程被调用如在 UI 主线程发布事件则直接在主线程处理事件如果在子线程发送事件则先将事件入队列然后通过 Handler 切换到主线程依次处理事件ThreadMode.MAIN_ORDERED无论在那个线程发送事件都先将事件入队列然后通过 Handler 切换到主线程依次处理事件注意该模式下可以确保 post() 的调用是非阻塞的ThreadMode.BACKGROUND表示订阅者的订阅方法在后台线程。如果发布事件的线程是 UI 主线程那么将开启一个后台线程执行订阅方法如果发布事件的线程是在后台线程那么事件处理函数就使用该线程ThreadMode.ASYNC表示无论发布事件的线程是哪一个订阅者的订阅方法始终会新建一个子线程来执行。所以这种情况下可以做耗时操作但是需要避免在同一时间进行大量的异步订阅控制并发线程的数量。
说了这么多最后再来看一下 EventBus 有何缺点
使用的时需定义很多 Event 类需要自己注册和反注册如果忘了反注册就会导致内存泄漏Event 在注册的时候会通过反射去遍历注册对象的方法并在其中找出带有 subscriber 标签的方法性能不高可以通过编译时解析注解优化运行时反射带来的性能损耗。
二、EventBus 使用
1.添加依赖
在 app 或底层 base 库中的 builde.gradle 文件中导入依赖库
imlementation ‘org.greenrobot:eventbus:3.2.0’2.EventBus 基本使用
通过 EventBus 的三个重要参与者Event、Subscriber、Publisher 来一步步学习 EventBus 的基本使用
2.1 定义事件类
public class EventMessageT {private int code; // 事件类型private T data; // 数据public EventMessage(int code, T data){this.codecode;this.datadata;}public int getCode() {return code;}public void setCode(int code) {this.code code;}public T getData() {return data;}public void setData(T data) {this.data data;}Overridepublic String toString() {return EventMessage{ code code , data data };}
}2.2 注册 EventBus
public class EventBusActivity extends AppCompatActivity {Overrideprotected void onCreate(Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);}Overrideprotected void onStart() {super.onStart();// 注册 EventBusEventBus.getDefault().register(this);}// 接收事件、线程模式为 ThreadMode.POSTINGSubscribe(threadMode ThreadMode.POSTING, priority 1)public void onReceiveMsg(EventMessage message){Log.e(EventBus_Subscriber, onReceiveMsg_POSTING: message.toString());}// 接收事件、线程模式为 ThreadMode.MAINSubscribe(threadMode ThreadMode.MAIN, priority 1)public void onReceiveMsg1(EventMessage message){Log.e(EventBus_Subscriber, onReceiveMsg_MAIN: message.toString());}// 接收事件、线程模式为 ThreadMode.MAIN_ORDEREDSubscribe(threadMode ThreadMode.MAIN_ORDERED, priority 1)public void onReceiveMsg2(EventMessage message){Log.e(EventBus_Subscriber, onReceiveMsg_MAIN_ORDERED: message.toString());}// 接收事件、线程模式为 ThreadMode.BACKGROUNDSubscribe(threadMode ThreadMode.BACKGROUND, priority 1)public void onReceiveMsg3(EventMessage message){Log.e(EventBus_Subscriber, onReceiveMsg_BACKGROUND: message.toString());}// 接收事件、线程模式为 ThreadMode.ASYNC、同时设置 sticky 为 true表示粘性事件Subscribe(threadMode ThreadMode.ASYNC, sticky true, priority 1)public void onReceiveMsg4(EventMessage message){Log.e(EventBus_Subscriber, onReceiveMsg__ASYNC: message.toString());}Overrideprotected void onDestroy() {super.onDestroy();// 解除注册的 EventBusEventBus.getDefault().unregister(this);}
}2.3 EventBus 发起通知
通过 EventBus#post(eventMessage) 方法或者 EventBus#postSticky(eventMessage) 方法来发起事件
OnClick(R2.id.send_common_event)
public void clickCommon(){EventMessage message new EventMessage(1, 发送普通事件);EventBus.getDefault().post(message);
}OnClick(R2.id.send_sticky_event)
public void clickSticky(){EventMessage message new EventMessage(1, 发送黏性事件);EventBus.getDefault().postSticky(message);
}至此通过 EventBus 的 post() 方法发起的事情在 EventBusActivity 中就可以收到并做后续的处理。postSticky() 方法最终也是调用的 EventBus 的 post() 方法后续通过分析源码来进行剖析其具体过程。 三、EventBus 源码详解
EventBus 的实现原理主要包括如下几个方面的内容
Subscribe 注解注册事件订阅方法取消注册发布、处理事件粘性事件Subscriber Index
1.Subscribe 注解
EventBus3.0 开始用 Subscribe 注解配置事件订阅方法其共有三个参数可选threadMode、boolean sticky、int priority。 完整的写法如下
Subscribe(threadMode ThreadMode.MAIN, sticky true, priority 1)
public void onReceiveMsg(EventMessage message) {Log.e(TAG, onReceiveMsg: message.toString());
}threadMode用来设置 onReceiveMsg() 方法将在哪个线程环境下被调用共有五种模式参考上面的简介sticky一个 Boolean 类型的变量默认值为 false即不开启黏性 sticky 特性。其作用是订阅者可以先不进行注册如果 post() 事件已经发出再注册订阅者同样可以接收到事件并进行处理priority优先级是一个 int 类型的变量默认值为 0。值越大优先级越高越优先接收到事件。注意只有在 post() 事件和事件接收处理处于同一个线程环境的时候才有意义。
具体看下 Subscribe 注解的实现
Documented
Retention(RetentionPolicy.RUNTIME)
Target({ElementType.METHOD})
public interface Subscribe { // 指定事件订阅方法的线程模式即在哪个线程执行事件订阅方法处理事件默认为 POSTING ThreadMode threadMode() default ThreadMode.POSTING; // 是否支持粘性事件默认为 false boolean sticky() default false; // 指定事件订阅方法的优先级默认为0如果多个事件订阅方法可以接收相同事件的则优先级高的先接收到事件 int priority() default 0;
} 在使用 Subscribe 注解时可以根据需求指定 threadMode、sticky、priority 三个属性值。
2.注册事件订阅方法 结合 EventBus 注册事件流程图便于更好的理解源码执行流程首先 EventBus 注册事件的方式如下
EventBus.getDefault().register(this);EventBus#getDefault() 是一个单例方法保证当前只有一个 EventBus 实例对象
2.1 EventBus 实例
public class EventBus {static volatile EventBus defaultInstance;// 默认的 EventBusBuilder 实例对象private static final EventBusBuilder DEFAULT_BUILDER new EventBusBuilder();// 通过 double check 双重校验获取 EventBus 单例对象public static EventBus getDefault() {if (defaultInstance null) {synchronized (EventBus.class) {if (defaultInstance null) {defaultInstance new EventBus();}}}return defaultInstance;}// 创建一个新的EventBus实例每个实例都是一个单独的作用域事件在其中传递。// 要使用中央总线请考虑{link#getDefault}public EventBus() {// 继续调用 EventBus 的另一个有参构造函数传入默认的 EventBusBuilder 来完成它相关属性的初始化this(DEFAULT_BUILDER);}EventBus(EventBusBuilder builder) {subscriptionsByEventType new HashMap();typesBySubscriber new HashMap();stickyEvents new ConcurrentHashMap();mainThreadPoster new HandlerPoster(this, Looper.getMainLooper(), 10);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;}
}如果 defaultInstance 为 null则新建一个 EventBus 实例对象赋值给 defaultInstance。最终通过调用 EventBus 的另一个有参构造函数传入默认的 EventBusBuilder 来完成其相关属性的初始化。
可以通过 Builder 模式来支持用 EventBusBuilder 对 EventBus 进行一些属性的配置例如用如下方式注册事件
EventBus.builder().eventInheritance(false).logSubscriberExceptions(false).build().register(this);2.2 EventBus 注册
public class EventBus {private final SubscriberMethodFinder subscriberMethodFinder;// 注册订阅者 subscriber 以接收事件订阅者一旦对接收事件不再感兴趣就必须调用{link #unregister(Object)}public void register(Object subscriber) {// 获取当前要注册类的 Class 对象 Class? subscriberClass subscriber.getClass();// 根据 Class 查找当前类中订阅了事件的方法集合即使用了 Subscribe 注解、有 public 修饰符、一个参数的方法 // SubscriberMethod类主要封装了符合条件方法的相关信息Method对象、线程模式、事件类型、优先级、是否是粘性事等 ListSubscriberMethod subscriberMethods subscriberMethodFinder.findSubscriberMethods(subscriberClass);synchronized (this) {// 循环遍历订阅了事件的方法集合以完成注册for (SubscriberMethod subscriberMethod : subscriberMethods) {subscribe(subscriber, subscriberMethod);}}}
}EventBus#register() 方法的执行流程如下
通过 SubscriberMethodFinder#findSubscriberMethods() 方法根据当前要注册类的 Class 对象查找当前类中订阅了事件的方法集合 List即找到使用了 Subscribe 注解、有 public 修饰符、一个参数的方法其中 SubscriberMethod 类主要封装了符合条件方法的相关信息Method 对象、线程模式、事件类型、优先级、是否是粘性事等循环遍历订阅了事件的方法集合通过 EventBus#subscribe() 方法完成注册。
2.2.1 SubscriberMethodFinder#findSubscriberMethods()
class SubscriberMethodFinder {// METHOD_CACHE是一个ConcurrentHashMap保存了subscriberClass和对应SubscriberMethod的集合以提高注册效率避免重复查找private static final MapClass?, ListSubscriberMethod METHOD_CACHE new ConcurrentHashMap();ListSubscriberMethod findSubscriberMethods(Class? subscriberClass) {// 获取 subscriberClass 类对应的 SubscriberMethod 的集合ListSubscriberMethod subscriberMethods METHOD_CACHE.get(subscriberClass);if (subscriberMethods ! null) { // 获取到且不为 null 则直接返回找到的 SubscriberMethod 的集合return subscriberMethods;}// ignoreGenereatedIndex 是用于标记是否忽略由 Builder 传入的 SubscriberInfoIndex// 由于使用了默认的 EventBusBuilder则 ignoreGeneratedIndex 属性默认为 falseif (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;}}
}SubscriberMethodFinder#findSubscriberMethods() 方法的执行流程如下
先从缓存集合 MapClass?, List METHOD_CACHE 中查找、获取 subscriberClass 类对应的 SubscriberMethod 的集合如果找到则直接返回如果查找不到则根据条件判断进行下一步的查找过程由于使用了默认的 EventBusBuilder因此 ignoreGeneratedIndex 属性默认为 false即忽略注解生成器所以调用 SubscriberMethodFinder#findUsingInfo() 方法进行查找最后将查找到的订阅事件的方法集合缓存到 METHOD_CACHE 中。
2.2.1.1 SubscriberMethodFinder#findUsingInfo()
class SubscriberMethodFinder {private ListSubscriberMethod findUsingInfo(Class? subscriberClass) {// 通过 SubscriberMethodFinder#prepareFindState() 方法从 FindState 池中获取到非空的 FindState 并返回FindState findState prepareFindState();findState.initForSubscriber(subscriberClass); // 初始化 FindState// 初始状态下 findState.clazz 就是 subscriberClass while (findState.clazz ! null) {// 由于在 FindState.initForSubscriber() 方法初始化时 subscriberInfo 赋值为 null// 且没有通过 EventBusBuilder 向 ListSubscriberInfoIndex subscriberInfoIndexes 集合中添加 SubscriberInfoIndexfindState.subscriberInfo getSubscriberInfo(findState);if (findState.subscriberInfo ! null) { // findState.subscriberInfo 为 nullSubscriberMethod[] array findState.subscriberInfo.getSubscriberMethods();for (SubscriberMethod subscriberMethod : array) {if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {findState.subscriberMethods.add(subscriberMethod);}}} else { // 通过反射查找订阅事件的方法 findUsingReflectionInSingleClass(findState);}// 修改 findState.clazz 为 subscriberClass 的父类 Class即需要遍历父类findState.moveToSuperclass();}// 查找到的方法保存在了 FindState 实例的 subscriberMethods 集合中// 使用 FindState.subscriberMethods 构建一个新的 ListSubscriberMethod然后释放掉 FindStatereturn getMethodsAndRelease(findState);}
}通过注释可知在 SubscriberMethodFinder#findUsingInfo() 方法会在当前要注册的类以及其父类中查找订阅事件的方法FindState 类是 SubscriberMethodFinder 的内部类用来辅助查找订阅事件的方法通过条件判断可知接下来将通过 SubscriberMethodFinder#findUsingReflectionInSingleClass() 方法通过反射查找订阅事件的方法。 SubscriberMethodFinder 类中维护了一个 FindState 池是一个默认大小为 4 的数组通过 SubscriberMethodFinder#prepareFindState() 方法遍历该数组找到非 null 的 FindState 进行返回。而在 SubscriberMethodFinder#getMethodsAndRelease(findState) 方法中则是将搜寻的结果取出后对 FindState 进行 recycle之后再将其放回 FindState 池中。 2.2.1.2 SubscriberMethodFinder#findUsingReflectionInSingleClass()
class SubscriberMethodFinder {private void findUsingReflectionInSingleClass(FindState findState) {Method[] methods;try {// 获取订阅事件的 Method 列表使用 getDeclaredMethods() 方法其实是比 getMethods() 方法的效率更高的// 尤其是对于较复杂庞大的类如 Activity 类methods findState.clazz.getDeclaredMethods();} catch (Throwable th) {// 但有时会导致 NoClassDefFoundError此时采取备用方案使用 getMethods() 进行获取methods findState.clazz.getMethods();findState.skipSuperClasses true;}// 循环遍历当前注册类的 methods 数组筛选出符合条件的public、non-static、non-abstract 的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) { // 检查其参数个数是否符合 1 的要求Subscribe subscribeAnnotation method.getAnnotation(Subscribe.class);if (subscribeAnnotation ! null) { // 如果当前方法使用了 Subscribe 注解 Class? eventType parameterTypes[0]; // 得到该参数的类型// FindState.checkAdd()方法用来判断 FindState 的 anyMethodByEventType map 是否// 已经添加过以当前 eventType 为 key 的键值对没添加过则返回 true if (findState.checkAdd(method, eventType)) {// 得到 Subscribe 注解的 threadMode 属性值即线程模式ThreadMode threadMode subscribeAnnotation.threadMode();// 创建一个 SubscriberMethod 对象并添加到 subscriberMethods 集合 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);}}}
}SubscriberMethodFinder#findUsingReflectionInSingleClass() 方法的执行流程如下
获取订阅事件的 Method 列表注意使用 getDeclaredMethods() 方法其实是比 getMethods() 方法的效率更高的但有时会导致 NoClassDefFoundError此时采取备用方案再使用 getMethods() 进行获取循环遍历当前注册类的 methods 数组筛选出符合条件public、non-static、non-abstract 的然后获取符合条件的方法的所有参数类型如果参数个数符合 1 的要求且使用了 Subscribe 注解则通过 FindState.checkAdd() 方法来判断 FindState 的 MapClass, Object anyMethodByEventType 集合中是否已经添加过以当前参数的类型 eventType 为 key 的键值对如没添加过则返回 true随后创建一个 SubscriberMethod 对象并添加到 FindState 的 ListSubscriberMethod subscriberMethods 集合中。
2.2.1.3 SubscriberMethodFinder#FindState#checkAdd()
class SubscriberMethodFinder {static class FindState {final MapClass, Object anyMethodByEventType new HashMap();boolean checkAdd(Method method, Class? eventType) {// 2级检查:第一级通过事件类型(较快速)第二级检查需具有完整签名。通常订阅者不会监听相同事件类型的方法Object existing anyMethodByEventType.put(eventType, method);if (existing null) { // existing 为 null说明之前的集合没有当前要加入的订阅方法return true; // 直接返回 true} else {if (existing instanceof Method) {if (!checkAddWithMethodSignature((Method) existing, eventType)) {// Paranoia checkthrow new IllegalStateException();}// Put any non-Method object to consume the existing MethodanyMethodByEventType.put(eventType, this);}return checkAddWithMethodSignature(method, eventType);}}}
}FindState#checkAdd() 方法中将订阅事件的方法 Method 以方法的参数类型为 key 保存到 HashMapClass, Object anyMethodByEventType 集合中同时还会调用 FindState#checkAddWithMethodSignature() 方法将方法以方法的签名形式为方法名Event 类型名为 key 保存到 HashMapString, Class subscriberClassByMethodKey 集合中。
2.2.2 EventBus#subscribe()
在 EventBus#register() 方法中通过 SubscriberMethodFinder#findSubscriberMethods() 方法查找到当前要注册类及其父类中订阅了事件的方法集合 List subscriberMethods随后循环遍历该方法集合再通过 EventBus#subscribe() 方法完成注册
public class EventBus {// 保存以订阅方法的参数类型 eventType 为 keySubscription 对象集合为 value 的键值对的集合 HashMapprivate final MapClass?, CopyOnWriteArrayListSubscription subscriptionsByEventType;// 保存以当前要注册类的对象为 key注册类中订阅事件的方法的参数类型的集合为 value 的键值对的集合 HashMapprivate final MapObject, ListClass? typesBySubscriber;// 必须在同步块中调用EventBus 为方法的订阅过程进行了加锁保证了线程安全private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {Class? eventType subscriberMethod.eventType; // 得到当前订阅了事件的方法的参数类型// Subscription 类保存了要注册的类对象以及当前订阅的 subscriberMethod Subscription newSubscription new Subscription(subscriber, subscriberMethod);// 查找集合 subscriptionsByEventType 中是否存在以当前 eventType 为 key 的值 CopyOnWriteArrayListSubscription subscriptions subscriptionsByEventType.get(eventType);if (subscriptions null) { // 如果不存在则创建一个 subscriptions 集合并以当前订阅方法的参数类型为 key 保存到 subscriptionsByEventTypesubscriptions new CopyOnWriteArrayList();subscriptionsByEventType.put(eventType, subscriptions);} else {if (subscriptions.contains(newSubscription)) {throw new EventBusException(Subscriber subscriber.getClass() already registered to event eventType);}}// 将新创建的 newSubscription 对象按照优先级 priority 的顺序添加到 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;}}// 查找是否存在当前要注册的类对象所对应的方法的参数类型集合ListClass? subscribedEvents typesBySubscriber.get(subscriber);if (subscribedEvents null) {// 不存在则创建一个集合 subscribedEvents并以当前要注册类的对象为 key 保存到 typesBySubscribersubscribedEvents 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 - ListClass).SetMap.EntryClass?, Object entries stickyEvents.entrySet();for (Map.EntryClass?, 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);}}}
}EventBus#subscribe() 方法中新建 Subscription 实例对象保存要注册的类对象以及当前类中订阅的 subscriberMethod将新建的 Subscription 实例对象保存到 MapClass?, CopyOnWriteArrayListSubscription subscriptionsByEventType 集合中同时将当前订阅事件方法的参数类型添加到 MapObject, ListClass? typesBySubscriber 集合中。流程至此EventBus 注册的核心流程的源码已经分析完。
3.EventBus 取消注册 结合 EventBus 取消注册流程图再来分析源码首先 EventBus 取消注册的方式如下
EventBus.getDefault().unregister(this);3.1 EventBus#unregister()
public class EventBus {// 保存以当前要注册类的对象为 key注册类中订阅事件的方法的参数类型的集合为 value 的键值对的集合 HashMapprivate final MapObject, ListClass? typesBySubscriber;// 取消给定订阅者所注册订阅的所有事件public synchronized void unregister(Object subscriber) {// 获取当前注册类对象对应的订阅事件方法的参数类型的集合 ListClass? subscribedTypes typesBySubscriber.get(subscriber);if (subscribedTypes ! null) {// 遍历订阅事件方法的参数类型集合释放之前保存的当前注册类中的 Subscriptionfor (Class? eventType : subscribedTypes) {unsubscribeByEventType(subscriber, eventType);}// 集合中删除以 subscriber 为 key 的键值对typesBySubscriber.remove(subscriber);} else {Log.w(TAG, Subscriber to unregister was not registered before: subscriber.getClass());}}
}EventBus#unregister() 方法首先获取当前注册类对象对应的订阅事件方法的参数类型的集合随后遍历订阅事件方法的参数类型集合调用 EventBus#unsubscribeByEventType() 方法释放之前保存的当前注册类中的 Subscription。最后从 MapObject, ListClass? typesBySubscriber 集合中删除以当前 subscriber 为 key 的键值对。
3.2 EventBus#unsubscribeByEventType()
public class EventBus {// 保存以订阅方法的参数类型 eventType 为 keySubscription 对象集合为 value 的键值对的集合 HashMapprivate final MapClass?, CopyOnWriteArrayListSubscription subscriptionsByEventType;// 只更新 subscriptionsByEventType 集合不更新 typebysubscriber 集合调用者必须更新 typebysubscriber 集合private void unsubscribeByEventType(Object subscriber, Class? eventType) {// 获取当前订阅方法的参数类型所对应的 Subscription 集合 ListSubscription subscriptions subscriptionsByEventType.get(eventType);if (subscriptions ! null) {int size subscriptions.size();for (int i 0; i size; i) { // 遍历 Subscription 集合 Subscription subscription subscriptions.get(i);// 如果当前 subscription 对象对应的注册类对象和要取消注册的注册类对象相同// 则从 Subscription 集合中删除当前 subscription 对象 if (subscription.subscriber subscriber) {subscription.active false;subscriptions.remove(i);i–;size–;}}}}
}EventBus#unsubscribeByEventType() 方法中获取当前订阅方法的参数类型所对应的 Subscription 集合遍历 Subscription 集合如果当前 subscription 对象所对应的注册类对象和要取消注册的注册类对象相同则从 Subscription 集合中删除。流程至此EventBus 取消注册的源码已经分析完。
4.EventBus 发布、处理事件
EventBus 发布事件的方式如下
EventBus.getDefault().post(new EventMessage(1, 事件 1));4.1 EventBus#post()
public class EventBus {// currentPostingThreadState 是一个 PostingThreadState 类型的 ThreadLocal // PostingThreadState 类保存了事件队列和线程模式等信息 private final ThreadLocalPostingThreadState currentPostingThreadState new ThreadLocalPostingThreadState() {Overrideprotected PostingThreadState initialValue() {return new PostingThreadState();}}; // 将给定的事件 event 发布到事件总线 EventBuspublic void post(Object event) {// 获取 ThreadLocal 中保存的 PostingThreadState 实例对象PostingThreadState postingState currentPostingThreadState.get();ListObject eventQueue postingState.eventQueue;eventQueue.add(event); // 将要发送的事件添加到事件队列if (!postingState.isPosting) { // isPosting 默认为 false postingState.isMainThread Looper.getMainLooper() Looper.myLooper(); // 是否为主线程postingState.isPosting true; // isPosting 置为 true使得事件 post 的过程中 当前线程的其他 post 事件无法被响应if (postingState.canceled) {throw new EventBusException(Internal error. Abort state was not reset);}try {while (!eventQueue.isEmpty()) { // 遍历事件队列 // EventBus.postSingleEvent() 发送单个事件 // eventQueue.remove(0)从事件队列移除事件 postSingleEvent(eventQueue.remove(0), postingState);}} finally {postingState.isPosting false; // 当 post 过程结束后再将 isPosting 置为 falsepostingState.isMainThread false;}}}
}EventBus#post() 方法获取 ThreadLocal 中保存的 PostingThreadState 实例对象将要发送的事件添加到事件队列 PostingThreadState.eventQueue 中随后遍历事件队列调用 EventBus#postSingleEvent() 方法发送单个事件。
4.2 EventBus#postSingleEvent()
public class EventBus { private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {Class? eventClass event.getClass();boolean subscriptionFound false;if (eventInheritance) { // eventInheritance默认为true表示是否向上查找事件的父类// 查找当前事件类型 Class 及其父类、接口等保存到集合 MapClass?, ListClass? eventTypesCachListClass? eventTypes lookupAllEventTypes(eventClass);int countTypes eventTypes.size();for (int h 0; h countTypes; h) { // 遍历 eventTypesCach 集合继续处理事件 Class? clazz eventTypes.get(h);subscriptionFound | postSingleEventForEventType(event, postingState, clazz);}} else {subscriptionFound postSingleEventForEventType(event, postingState, eventClass);}if (!subscriptionFound) {if (logNoSubscriberMessages) {Log.d(TAG, No subscribers registered for event eventClass);}if (sendNoSubscriberEvent eventClass ! NoSubscriberEvent.class eventClass ! SubscriberExceptionEvent.class) {post(new NoSubscriberEvent(this, event));}}}
}EventBus#postSingleEvent() 方法中根据 eventInheritance 属性决定是否向上遍历事件的父类型将获取到的当前事件类型 Class 及其父类、接口等保存到 MapClass?, ListClass? eventTypesCach 集合中然后遍历刚获取的集合对集合中的每一个 Class 调用 EventBus#postSingleEventForEventType() 方法进一步处理。
4.3 EventBus#postSingleEventForEventType()
public class EventBus { // 保存以订阅方法的参数类型 eventType 为 keySubscription 对象集合为 value 的键值对的集合 HashMapprivate final MapClass?, CopyOnWriteArrayListSubscription subscriptionsByEventType;private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class? eventClass) {CopyOnWriteArrayListSubscription subscriptions;synchronized (this) {// 获取事件类型对应的 Subscription 集合subscriptions subscriptionsByEventType.get(eventClass);}// 如果已有订阅者订阅了对应类型的事件if (subscriptions ! null !subscriptions.isEmpty()) {for (Subscription subscription : subscriptions) {postingState.event event; // PostingThreadState 记录事件postingState.subscription subscription; // PostingThreadState 记录对应的 subscriptionboolean aborted false;try {// EventBus.postToSubscription() 方法对事件进行处理 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;}
}EventBus#postSingleEventForEventType() 方法中首先同步加锁获取事件类型对应的 Subscription 集合如果获得的集合不为 null表示已有订阅者订阅了对应类型的事件则遍历 Subscription 集合为每一个 Subscription 调用 EventBus#postToSubscription() 方法来处理事件。
4.4 EventBus#postToSubscription()
public class EventBus { private final HandlerPoster mainThreadPoster;private final BackgroundPoster backgroundPoster;private final AsyncPoster asyncPoster;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 {// 如果是在子线程发送事件则将事件入队列通过 Handler 切换到主线程执行处理事件 // mainThreadPoster 不为空mainThreadPoster.enqueue(subscription, event);}break;case MAIN_ORDERED: // 无论在那个线程发送事件都先将事件入队列然后通过 Handler 切换到主线程依次处理事件if (mainThreadPoster ! null) { // mainThreadPoster 不为空将事件入队列然后通过 Handler 切换到主线程依次处理事件mainThreadPoster.enqueue(subscription, event); } else { // 否者直接在主线程通过反射处理事件invokeSubscriber(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);}}
}EventBus#postToSubscription() 方法根据订阅事件方法的线程模式、以及发送事件的线程来判断如何处理事件处理方式主要有两种
在相应线程直接通过 EventBus#invokeSubscriber() 方法通过反射来执行订阅事件的方法此时发送出去的事件就被订阅者接收并做相应处理通过不同的 Poster 将事件入队然后采用队列的方式做进一步处理。
4.4.1 EventBus#invokeSubscriber()
public class EventBus { void invokeSubscriber(Subscription subscription, Object event) {try { // 反射调用来执行订阅事件的方法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#invokeSubscriber() 方法中由 Subscription 实例保存的事件订阅方法通过反射来执行订阅者的事件订阅方法此时发布的事件就被订阅者接收并做相应处理。
4.4.2 HandlerPoster#enqueue()
final class HandlerPoster extends Handler {private final PendingPostQueue queue;private final int maxMillisInsideHandleMessage;private final EventBus eventBus;private boolean handlerActive;HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {super(looper);this.eventBus eventBus;this.maxMillisInsideHandleMessage maxMillisInsideHandleMessage;queue new PendingPostQueue();}void enqueue(Subscription subscription, Object event) {// 通过 PendingPost.obtainPendingPost() 方法从 pendingPostPool 缓存中获取 PendingPost 并赋值// 如果缓存中没有则由 subscription 和 event 新建一个 PendingPost 对象PendingPost pendingPost PendingPost.obtainPendingPost(subscription, event);synchronized (this) {queue.enqueue(pendingPost); // 通过 PendingPostQueue.enqueue() 入队if (!handlerActive) {handlerActive true;// 发送开始处理事件的消息handleMessage() 方法将被执行完成从子线程到主线程的切换if (!sendMessage(obtainMessage())) {throw new EventBusException(Could not send handler message);}}}}Overridepublic void handleMessage(Message msg) {boolean rescheduled false;try {long started SystemClock.uptimeMillis();while (true) { // 死循环遍历队列PendingPost pendingPost queue.poll(); // 出队获取 PendingPostif (pendingPost null) {synchronized (this) {// 再检查一次这次是同步的pendingPost queue.poll();if (pendingPost null) {handlerActive false; // 经过两次获取仍然为 null 则直接返回并置 handlerActive 为 falsereturn;}}}// 通过 EventBus.invokeSubscriber() 方法进一步处理 pendingPosteventBus.invokeSubscriber(pendingPost);long timeInMethod SystemClock.uptimeMillis() - started;if (timeInMethod maxMillisInsideHandleMessage) {if (!sendMessage(obtainMessage())) {throw new EventBusException(Could not send handler message);}rescheduled true;return;}}} finally {handlerActive rescheduled;}}
}HandlerPoster#enqueue() 方法首先通过 PendingPost.obtainPendingPost() 方法从 pendingPostPool 缓存中获取 PendingPost 并赋值传入的 subscription、event 对象如果缓存中获取不到则由 subscription 和 event 新建一个 PendingPost 对象并将 PendingPost 添加到 PendingPostQueue 队列中随后通过 Handler 切换到主线程在 Handler#handleMessage() 方法中将 PendingPost 对象循环出队列交给 EventBus#invokeSubscriber() 方法进行处理。
4.4.3 EventBus#invokeSubscriber()
public class EventBus {void invokeSubscriber(PendingPost pendingPost) {Object event pendingPost.event;Subscription subscription pendingPost.subscription;PendingPost.releasePendingPost(pendingPost); // 释放 PendingPost 引用的资源if (subscription.active) {// 最终通过反射来执行订阅事件的方法invokeSubscriber(subscription, event);}}
}EventBus#invokeSubscriber() 方法主要就是从 PendingPost 中取出之前保存的 event、subscription然后通过反射来执行订阅事件的方法又回到了第一种处理方式。所以 HandlerPoster#enqueue(subscription, event) 方法的核心就是先将将事件入队列然后通过 Handler 从子线程切换到主线程中去处理事件。
4.4.4 BackgroundPoster#enqueue()
final class BackgroundPoster implements Runnable {private final PendingPostQueue queue;private final EventBus eventBus;private volatile boolean executorRunning;BackgroundPoster(EventBus eventBus) {this.eventBus eventBus;queue new PendingPostQueue();}public void enqueue(Subscription subscription, Object event) {// 通过 PendingPost.obtainPendingPost() 方法从 pendingPostPool 缓存中获取 PendingPost 并赋值// 如果缓存中没有则由 subscription 和 event 新建一个 PendingPost 对象PendingPost pendingPost PendingPost.obtainPendingPost(subscription, event);synchronized (this) {queue.enqueue(pendingPost); // 通过 PendingPostQueue.enqueue() 入队if (!executorRunning) {executorRunning true;// 通过线程池来执行当前 BackgroundPoster 的 run() 方法来进一步处理事件eventBus.getExecutorService().execute(this);}}}Overridepublic void run() {try {try {while (true) { // 死循环遍历队列PendingPost pendingPost queue.poll(1000); // 出队获取 PendingPostif (pendingPost null) {synchronized (this) {// 再检查一次这次是同步的pendingPost queue.poll();if (pendingPost null) {// 经过两次获取仍然为 null 则直接返回并置 handlerActive 为 falseexecutorRunning false;return;}}}// 通过 EventBus.invokeSubscriber() 方法进一步处理 pendingPosteventBus.invokeSubscriber(pendingPost);}} catch (InterruptedException e) {Log.w(Event, Thread.currentThread().getName() was interruppted, e);}} finally {executorRunning false;}}
}BackgroundPoster#enqueue() 方法跟 HandlerPoster#enqueue() 方法的功能差不多核心也是先将事件加入到 PendingPostQueue 队列然后再出队列。不同之处是 BackgroundPoster 是通过线程池来执行其 run() 方法最后交给 EventBus#invokeSubscriber() 方法进行处理。
4.4.5 AsyncPoster#enqueue()
class AsyncPoster implements Runnable {private final PendingPostQueue queue;private final EventBus eventBus;AsyncPoster(EventBus eventBus) {this.eventBus eventBus;queue new PendingPostQueue();}public void enqueue(Subscription subscription, Object event) {// 通过 PendingPost.obtainPendingPost() 方法从 pendingPostPool 缓存中获取 PendingPost 并赋值// 如果缓存中没有则由 subscription 和 event 新建一个 PendingPost 对象PendingPost pendingPost PendingPost.obtainPendingPost(subscription, event);queue.enqueue(pendingPost); // 通过 PendingPostQueue.enqueue() 入队// 通过线程池来执行当前 AsyncPoster 的 run() 方法来进一步处理事件eventBus.getExecutorService().execute(this);}Overridepublic void run() {PendingPost pendingPost queue.poll();if(pendingPost null) {throw new IllegalStateException(No pending post available);}// 通过 EventBus.invokeSubscriber() 方法进一步处理 pendingPosteventBus.invokeSubscriber(pendingPost);}
}AsyncPoster#enqueue() 方法跟 HandlerPoster#enqueue() 方法差不多核心也是先将事件加入到 PendingPostQueue 队列然后再出队列随后通过线程池来执行其 run() 方法最后交给 EventBus#invokeSubscriber() 方法进行处理。流程至此EventBus 发布事件与处理事件的源码已经分析完。
EventBus 发布事件(包括粘性事件)及处理流程 5.EventBus 粘性事件
一般情况使用 EventBus 都是准备好订阅事件的方法然后注册事件最后在发布事件即要先有事件的接收者(订阅者)。但粘性事件却恰恰相反可以先发布事件后续再准备订阅事件的方法、以及注册事件。
发布粘性事件通过如下方式
EventBus.getDefault().postSticky(new EventMessage(2, 粘性事件));5.1 EventBus#postSticky()
public class EventBus {// 发布粘性事件时保存事件的类型和对应事件本身private final MapClass?, Object stickyEvents;// 将给定的事件发布到 EventBus 并保持该事件(因为它具有粘性)。// 相同事件类型、最近的粘性事件保存在内存中供订阅者使用 Subscribe#sticky() 访问public void postSticky(Object event) {synchronized (stickyEvents) {// 将发布的事件和事件类型保存到 stickyEventsstickyEvents.put(event.getClass(), event);}// 保存后再调用 EventBus#post(event) 方法以防订阅者想立即删除post(event);}
}EventBus#postSticky() 方法执行流程如下
将事件类型和对应事件保存到 MapClass?, Object stickyEvents 集合中等待后续使用通过 EventBus#post(event) 方法继续发布事件。因此如果在发布粘性事件前已经有了对应类型事件的订阅者即使它是非粘性的依然可以接收到发布的粘性事件。
通过 EventBus#post(event) 方法发布粘性事件流程在前面已经分析过在前面分析 EventBus#subscribe() 方法时关于粘性事件的处理过程还没分析下面一起来剖析一下这段代码。
5.2 EventBus#subscribe()
public class EventBus {// 发布粘性事件时保存事件的类型和对应事件本身private final MapClass?, Object stickyEvents;private final boolean eventInheritance; // 默认为 true表示是否向上查找事件的父类// 必须在同步块中调用EventBus 为方法的订阅过程进行了加锁保证了线程安全private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {……// 如果当前订阅事件方法的 Subscribe 注解的 sticky 属性为 true即该方法可接受粘性事件if (subscriberMethod.sticky) {if (eventInheritance) { // 默认为 true表示向上查找事件的父类// 须考虑 eventType 所有子类的现有粘性事件。注意对于粘性事件较多的情况遍历所有事件效率不高// 因此要更改数据结构使得查找更加有效(如存储父类的子类集合Class - ListClass)SetMap.EntryClass?, Object entries stickyEvents.entrySet();for (Map.EntryClass?, Object entry : entries) {Class? candidateEventType entry.getKey();// 如果 candidateEventType 是 eventType 的子类if (eventType.isAssignableFrom(candidateEventType)) {Object stickyEvent entry.getValue(); // 获得对应的事件// 通过 EventBus.checkPostStickyEventToSubscription() 方法处理粘性事件checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}} else {Object stickyEvent stickyEvents.get(eventType);// 通过 EventBus.checkPostStickyEventToSubscription() 方法处理粘性事件checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}}
}EventBus#subscribe() 方法中如果当前订阅事件方法的 Subscribe 注解的 sticky 属性为 true即该方法可接受粘性事件。遍历 EventBus#postSticky() 方法保存到 MapClass?, Object stickyEvents 集合中的粘性事件如果 stickyEvents 中取出事件的事件类型与当前订阅方法接收的事件类型相同或者是其子类则取出 stickyEvents 中对应事件类型的具体事件然后通过 EventBus.checkPostStickyEventToSubscription() 方法处理粘性事件。
5.3 EventBus#checkPostStickyEventToSubscription()
public class EventBus {// 发布粘性事件时保存事件的类型和对应事件本身private final MapClass?, Object stickyEvents;private final boolean eventInheritance; // 默认为 true表示是否向上查找事件的父类private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {if (stickyEvent ! null) {// 如果订阅者试图中止当前事件则将失败(在发布状态下事件无法追踪)postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() Looper.myLooper());}}
}EventBus#checkPostStickyEventToSubscription() 方法在判空操作通过后通过 EventBus#postToSubscription() 方法完成粘性事件的处理处理流程前面已经分析过不再重复分析。流程至此EventBus 粘性事件的发布与处理流程已经分析完。
6.EventBus 之 Subscriber Index
通过上面几节的分析可知EventBus 在项目运行时默认是通过反射来查找订阅事件的方法信息如果项目中存在大量的订阅事件的方法通过反射必然会对项目运行时的性能产生影响。EventBus 也考虑到了这个问题因此除了默认的反射之外还提供了在项目编译时通过注解处理器(APT 全称Annotation Processing Tool)查找订阅事件方法信息的方式在编译期生成一个辅助的索引类 Subscriber Index 来保存这些信息。
要在项目编译时查找订阅事件的方法信息首先要在 app 的 build.gradle 中加入如下配置
android {defaultConfig {javaCompileOptions {annotationProcessorOptions {// 根据项目实际情况指定辅助索引类的名称和包名arguments [ eventBusIndex : com.xxx.xxx.EventBusIndex ]}}}
}
dependencies {compile org.greenrobot:eventbus:3.2.0// 引入注解处理器annotationProcessor org.greenrobot:eventbus-annotation-processor:3.2.0
}然后在项目的 Application 中添加如下配置以生成一个默认的 EventBus 单例
public class AndroidApplication extends Application implements Application.ActivityLifecycleCallbacks {Overridepublic void onCreate() {super.onCreate();registerActivityLifecycleCallbacks(this);EventBus.builder().addIndex(new EventBusIndex()).installDefaultEventBus();}
}用法还是和上面的例子一样只是在项目编译时会生成对应的 EventBusIndex 类(这里是在项目的底层 baselibrary 进行配置的进行了封装如果是简单使用放到 app 模块即可)
6.1 EventBusIndex
// 这个类是由 EventBus 生成的不要编辑
public class EventBusIndex implements SubscriberInfoIndex {// 保存当前注册类的 Class 类型和其中事件订阅方法的信息private static final MapClass?, SubscriberInfo SUBSCRIBER_INDEX;static {SUBSCRIBER_INDEX new HashMapClass?, SubscriberInfo();putIndex(new SimpleSubscriberInfo(com.xxx.xxx.baselibrary.mvp.view.BaseMVPActivity.class, true,new SubscriberMethodInfo[] {new SubscriberMethodInfo(onEvent, java.util.Map.class, ThreadMode.MAIN),}));}private static void putIndex(SubscriberInfo info) {SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);}Overridepublic SubscriberInfo getSubscriberInfo(Class? subscriberClass) {SubscriberInfo info SUBSCRIBER_INDEX.get(subscriberClass);if (info ! null) {return info;} else {return null;}}
}EventBusIndex 是由 EventBus 生成的不要编辑。其内部首先在静态代码块内新建 HashMap 保存当前注册类的 Class 类型和其中事件订阅方法的信息然后通过 EventBusIndex#putIndex() 方法将新建的 SimpleSubscriberInfo 实例对象添加到新建的 HashMap 中保存。
接下来通过源码剖析使用 Subscriber Index 时 EventBus 的注册流程由前面的使用代码可知期首先创建一个 EventBusBuilder 实例对象然后通过其 addIndex() 方法添加索引类的实例
6.2 EventBusBuilder#addIndex()
public class EventBusBuilder {ListSubscriberInfoIndex subscriberInfoIndexes;/** Adds an index generated by EventBus annotation preprocessor. /// 添加一个由 EventBus 注解处理器生成的索引 SubscriberInfoIndexpublic EventBusBuilder addIndex(SubscriberInfoIndex index) {if(subscriberInfoIndexes null) {subscriberInfoIndexes new ArrayList();}subscriberInfoIndexes.add(index);return this;}
}EventBusBuilder#addIndex() 方法把生成的索引类的实例保存在 ListSubscriberInfoIndex subscriberInfoIndexes 集合中。
6.2 EventBusBuilder#installDefaultEventBus()
public class EventBusBuilder {/** 安装由 EventBus#getDefault() 方法返回的默认 EventBus使用 EventBusBuilder 的值* 必须在第一次使用默认 EventBus 之前完成一次** 如果已经有一个默认的 EventBus 实例抛出 EventBusException*/public EventBus installDefaultEventBus() {synchronized (EventBus.class) {if (EventBus.defaultInstance ! null) {throw new EventBusException(Default instance already exists. It may be only set once before its used the first time to ensure consistent behavior.);}EventBus.defaultInstance build();return EventBus.defaultInstance;}}// 基于当前配置构建 EventBus 实例对象public EventBus build() {// this 代表当前 EventBusBuilder 对象return new EventBus(this);}
}EventBusBuilder#installDefaultEventBus() 方法就是使用当前 EventBusBuilder 实例对象构建一个 EventBus 实例然后赋值给 EventBus 的 defaultInstance 成员变量这样通过 EventBusBuilder 配置的 Subscriber Index 也就传递到了 EventBus 实例中。
6.3 SubscriberMethodFinder#findUsingInfo()
由于配置使用了 Subscriber Index 索引类回头再看 SubscriberMethodFinder#findUsingInfo() 方法执行流程将会有所不同
class SubscriberMethodFinder {private ListSubscriberMethod findUsingInfo(Class? subscriberClass) {// 通过 SubscriberMethodFinder#prepareFindState() 方法从 FindState 池中获取到非空的 FindState 并返回FindState findState prepareFindState();findState.initForSubscriber(subscriberClass); // 初始化 FindState// 初始状态下 findState.clazz 就是 subscriberClass while (findState.clazz ! null) {// 虽然 FindState.initForSubscriber() 方法初始化时 subscriberInfo 赋值为 null// 但此时通过 EventBusBuilder 向 ListSubscriberInfoIndex subscriberInfoIndexes 集合中添加了// SubscriberInfoIndex 的实现类 EventBusIndex 实例对象因此getSubscriberInfo() 方法将返回// EventBusIndex#getSubscriberInfo() 方法的返回值这里将返回 SimpleSubscriberInfo 实例对象// 该实例对象是在 EventBusIndex 初始化时创建的将返回的该实例对象赋值给 FindState.subscriberInfo findState.subscriberInfo getSubscriberInfo(findState);if (findState.subscriberInfo ! null) { // findState.subscriberInfo 此时不为 null// 通过 SimpleSubscriberInfo.getSubscriberMethods() 方法获得当前注册类中所有订阅了事件的方法SubscriberMethod[] array findState.subscriberInfo.getSubscriberMethods();for (SubscriberMethod subscriberMethod : array) {// FindState.checkAdd()方法用来判断 FindState 的 anyMethodByEventType map 是否// 已经添加过以当前 eventType 为 key 的键值对没添加过则返回 true if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {// 将 SubscriberMethod 对象添加到 subscriberMethods 集合 findState.subscriberMethods.add(subscriberMethod);}}} else { // 通过反射查找订阅事件的方法 findUsingReflectionInSingleClass(findState);}// 修改 findState.clazz 为 subscriberClass 的父类 Class即需要遍历父类findState.moveToSuperclass();}// 查找到的方法保存在了 FindState 实例的 subscriberMethods 集合中// 使用 FindState.subscriberMethods 构建一个新的 ListSubscriberMethod然后释放掉 FindStatereturn getMethodsAndRelease(findState);}
}SubscriberMethodFinder#findUsingInfo() 方法中由于配置使用了 Subscriber Index此时 SubscriberMethodFinder#getSubscriberInfo() 方法的返回值不再为 null具体来看一下该方法的执行流程。
6.3.1 SubscriberMethodFinder#getSubscriberInfo()
class SubscriberMethodFinder {private SubscriberInfo getSubscriberInfo(FindState findState) {// FindState.initForSubscriber() 方法初始化时 subscriberInfo 赋值为 null因此该条件不成立if (findState.subscriberInfo ! null findState.subscriberInfo.getSuperSubscriberInfo() ! null) {SubscriberInfo superclassInfo findState.subscriberInfo.getSuperSubscriberInfo();if (findState.clazz superclassInfo.getSubscriberClass()) {return superclassInfo;}}// 通过 EventBusBuilder 向 ListSubscriberInfoIndex subscriberInfoIndexes 集合中添加了// SubscriberInfoIndex 的实现类 EventBusIndex 实例对象if (subscriberInfoIndexes ! null) { // subscriberInfoIndexes 不为 nullfor (SubscriberInfoIndex index : subscriberInfoIndexes) { // 遍历索引类实例集合// 根据注册类的 Class 类查找 SubscriberInfoSubscriberInfo info index.getSubscriberInfo(findState.clazz);if (info ! null) {return info;}}}return null;}
}SubscriberMethodFinder#getSubscriberInfo() 方法遍历 ListSubscriberInfoIndex subscriberInfoIndexes 集合根据注册类的 Class 类查找 SubscriberInfo此时将返回 EventBusIndex 初始化时创建的 SimpleSubscriberInfo 实例对象。
6.3.2 SimpleSubscriberInfo#getSubscriberMethods()
public class SimpleSubscriberInfo extends AbstractSubscriberInfo {Overridepublic 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;}
}SimpleSubscriberInfo#getSubscriberMethods() 方法的主要作用是获取当前注册类中所有订阅了事件的方法。
流程至此EventBus 使用 Subscriber Index 的主要源码分析完毕其它的和之前的注册订阅流程一样。
小结
Subscriber Index 的核心就是项目编译时使用注解处理器生成保存事件订阅方法信息的索引类然后项目运行时将索引类实例设置到 EventBus 中这样当注册 EventBus 时从索引类取出当前注册类对应的事件订阅方法信息以完成最终的注册避免了运行时反射处理的过程所以在性能上会有质的提高。项目中可以根据实际的需求决定是否使用 Subscriber Index。 总结
EventBus 底层采用的是注解和反射的方式来获取订阅方法信息整个 EventBus 可以看出事件是被观察者订阅者类是观察者当事件出现或者发布变更的时候会通过 EventBus 通知观察者使得观察者的订阅方法能够被自动调用
注意项目中根据实际需求决定是否使用如果滥用的话各种逻辑交叉在一起也可能会给后期的维护带来困难。
参考
greenrobot/EventBusgithub.com/greenrobot/EventBus
相关文章
-
360网站挂马检测网络服务有点问题别紧张试试看刷新页面
360网站挂马检测网络服务有点问题别紧张试试看刷新页面
- 技术栈
- 2026年03月17日
-
360网站seo怎么做重庆的电子商务网站
360网站seo怎么做重庆的电子商务网站
- 技术栈
- 2026年03月17日
-
360网站 备案php网站有点
360网站 备案php网站有点
- 技术栈
- 2026年03月17日
-
360网站图标怎么做的新淘客wordpress
360网站图标怎么做的新淘客wordpress
- 技术栈
- 2026年03月17日
-
360网站咋做学院网络营销策划方案
360网站咋做学院网络营销策划方案
- 技术栈
- 2026年03月17日
-
360网站在系统那里微信营销软件商城
360网站在系统那里微信营销软件商城
- 技术栈
- 2026年03月17日






