目录
- 一、概述
- 二、 EventBus 整体架构
-
-
- 核心设计模式
-
- 架构概览
-
- 二、 核心源码解析
-
-
- 注册过程分析
-
- `subscribe()` 方法详解:
-
- 事件发布流程
-
- 分发单个事件:
-
- 线程模式处理
-
- 订阅方法查找器(SubscriberMethodFinder)
-
- 反射查找逻辑:
-
- 四、 核心数据结构
-
-
- 主要存储结构
-
- 关键对象定义
-
- 五、 性能优化设计
-
-
- 缓存机制
-
- 编译时索引优化(EventBus 3+)
-
- 六、 线程处理实现(Poster)
-
-
- HandlerPoster 示例(主线程调度)
-
- 七、 注意事项
-
-
- 及时反注册
-
- 谨慎使用粘性事件
-
- 避免过度使用
-
- 注意线程安全
-
- 混淆配置
-
- 八、 总结
-
- 1.设计亮点
- 2.优势与价值
一、概述
EventBus 是一个基于 发布-订阅(Publish-Subscribe)模式 的事件总线框架,广泛应用于 Android 组件间的通信。它通过解耦组件之间的依赖关系,提升代码的可维护性和灵活性。
二、 EventBus 整体架构
1. 核心设计模式
设计模式 | 作用说明 |
---|---|
观察者模式 | 实现事件的发布与订阅机制,核心逻辑所在 |
单例模式 | 默认提供全局唯一的 EventBus 实例 |
建造者模式 | 用于灵活配置自定义 EventBus 实例 |
策略模式 | 不同 ThreadMode 对应不同的线程调度策略 |
2. 架构概览
发布者 (Publisher) → EventBus → 订阅者 (Subscriber)
↓ ↓
post(event) @Subscribe方法
二、 核心源码解析
1. 注册过程分析
java
// EventBus.java
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods =
subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
subscribe()
方法详解:
java
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Already registered to event " + eventType);
}
}
// 按优先级插入
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
// 记录订阅者关注的所有事件类型
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
// 处理粘性事件
if (subscriberMethod.sticky) {
Object stickyEvent = stickyEvents.get(eventType);
if (stickyEvent != null) {
postToSubscription(newSubscription, stickyEvent,
isMainThread() && subscriberMethod.threadMode == ThreadMode.MAIN);
}
}
}
关键点:
- 使用
CopyOnWriteArrayList
保证并发安全。 - 支持按优先级排序,高优先级先接收事件。
- 粘性事件在注册后立即触发。
2. 事件发布流程
java
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread();
postingState.isPosting = true;
try {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
分发单个事件:
java
private void postSingleEvent(Object event, PostingThreadState postingState) {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
for (Class<?> clazz : eventTypes) {
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) {
post(new NoSubscriberEvent(this, event));
}
}
}
特性支持:
- 支持事件继承:父类或接口事件也可被匹配。
- 若无订阅者,可发送
NoSubscriberEvent
做兜底处理。
3. 线程模式处理
java
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 {
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
if (mainThreadPoster != null) {
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);
}
}
五种线程模式:
模式 | 描述 |
---|---|
POSTING |
在发布线程直接执行(默认) |
MAIN |
总是在主线程执行 |
MAIN_ORDERED |
主线程中有序排队执行 |
BACKGROUND |
后台线程执行(非主线程时直接调用) |
ASYNC |
异步线程池执行,不阻塞任何线程 |
4. 订阅方法查找器(SubscriberMethodFinder)
java
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) return subscriberMethods;
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass); // 使用编译期索引
}
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
反射查找逻辑:
java
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>();
Class<?> clazz = subscriberClass;
while (clazz != null) {
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
Subscribe annotation = method.getAnnotation(Subscribe.class);
if (annotation != null) {
Class<?> eventType = parameterTypes[0];
SubscriberMethod subscriberMethod = new SubscriberMethod(
method, eventType, annotation.threadMode(),
annotation.priority(), annotation.sticky()
);
subscriberMethods.add(subscriberMethod);
}
}
}
}
clazz = clazz.getSuperclass();
}
return subscriberMethods;
}
优化点:
- 跳过系统类包(java., android.),减少无效扫描。
- 缓存结果避免重复反射。
- 支持从父类中查找
@Subscribe
方法。
四、 核心数据结构
1. 主要存储结构
java
public class EventBus {
// 事件类型 → 所有订阅者的映射
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
// 订阅者对象 → 其订阅的所有事件类型的映射
private final Map<Object, List<Class<?>>> typesBySubscriber;
// 粘性事件缓存:事件类型 → 最新事件实例
private final Map<Class<?>, Object> stickyEvents;
// 当前线程的发布状态(ThreadLocal)
private final ThreadLocal<PostingThreadState> currentPostingThreadState;
}
2. 关键对象定义
java
public class SubscriberMethod {
final Method method;
final ThreadMode threadMode;
final Class<?> eventType;
final int priority;
final boolean sticky;
}
public class Subscription {
final Object subscriber;
final SubscriberMethod subscriberMethod;
}
五、 性能优化设计
1. 缓存机制
java
// 避免重复反射
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE =
new ConcurrentHashMap<>();
// 事件继承链缓存
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
2. 编译时索引优化(EventBus 3+)
使用 APT 在编译阶段生成索引类,避免运行时反射开销。
java
public class MyEventBusIndex implements SubscriberInfoIndex {
private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX = new HashMap<>();
static {
putIndex(new SimpleSubscriberInfo(MainActivity.class, true,
new SubscriberMethodInfo[] {
new SubscriberMethodInfo("onMessageEvent", MessageEvent.class, ThreadMode.MAIN),
new SubscriberMethodInfo("onOtherEvent", OtherEvent.class, ThreadMode.BACKGROUND)
}));
}
}
💡 优势:
- 显著提升注册速度。
- 减少冷启动耗时。
- 更适合大型项目。
六、 线程处理实现(Poster)
1. HandlerPoster 示例(主线程调度)
java
final static class HandlerPoster extends Handler implements Poster {
private final PendingPostQueue queue;
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
sendMessage(obtainMessage());
}
}
}
@Override
public void handleMessage(Message msg) {
try {
long started = SystemClock.uptimeMillis();
while (true) {
PendingPost pendingPost = queue.poll();
if (pendingPost == null) break;
eventBus.invokeSubscriber(pendingPost);
// 控制单次处理时间,防止 ANR
if (SystemClock.uptimeMillis() - started > maxMillisInsideHandleMessage) {
sendMessage(obtainMessage());
return;
}
}
} finally {
handlerActive = false;
}
}
}
设计亮点:
- 使用
Handler
将任务投递到主线程。 - 采用
PendingPostQueue
缓冲待处理事件。 - 限制单次处理时长,保障 UI 流畅。
|
七、 注意事项
1. 及时反注册
java
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
❗未反注册会导致内存泄漏!
2. 谨慎使用粘性事件
- 粘性事件长期驻留内存。
- 接收后建议手动清除:
removeStickyEvent()
。
3. 避免过度使用
- 过度依赖 EventBus 会使逻辑分散,难以追踪。
- 复杂业务推荐使用 ViewModel、LiveData 或 RxJava。
4. 注意线程安全
- 多线程环境下确保共享数据同步访问。
- 粘性事件可能被多个线程修改。
5. 混淆配置
proguard
-keepattributes Signature
-keepclassmembers class * {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
八、 总结
1.设计亮点
特性 | 说明 |
---|---|
✅ 优雅的 API 设计 | 注解驱动,register/unregister/post 三步完成通信 |
✅ 高效的线程切换 | 多种 ThreadMode 满足不同场景需求 |
✅ 性能优化充分 | 缓存 + 编译期索引大幅降低反射成本 |
✅ 支持事件继承 | 发送子类事件可通知父类订阅者 |
✅ 灵活配置能力 | 建造者模式构建自定义 EventBus 实例 |
✅ 内存安全管理 | 提供反注册机制,配合生命周期管理防泄漏 |
2.优势与价值
EventBus 通过精巧的设计,在保持简洁易用的同时,实现了强大的组件通信能力。其融合了多种经典设计模式,并结合 Android 平台特性做了深度优化,是 观察者模式在移动端的优秀实践范本。
尽管随着 Jetpack 组件(如 LiveData、Flow)的发展,部分场景下可替代 EventBus,但在跨模块通信、松耦合广播等场景中,EventBus 依然具有不可替代的价值。