EventBus 通过 线程模式(ThreadMode) 来区分接收事件的线程,开发者通过注解 @Subscribe(threadMode = ThreadMode.XXX) 指定订阅方法运行的线程。其核心实现依赖 Handler 和 线程池,以下是详细机制:
1. 线程模式(ThreadMode)分类
EventBus 提供 5 种线程模式,控制订阅方法的执行线程:
线程模式 执行线程 适用场景
POSTING (默认) 事件发布的线程 快速同步操作,避免线程切换开销(需注意线程安全)。
MAIN 主线程(UI 线程) 更新 UI,操作必须在主线程完成。
MAIN_ORDERED 主线程(有序队列) 类似 MAIN,但确保事件按顺序处理(避免并发问题)。
BACKGROUND 后台线程(非主线程) 轻量级耗时操作(如数据库读写),EventBus 内部使用线程池。
ASYNC 独立异步线程 长时间耗时操作(如网络请求),使用独立线程池,避免阻塞主线程或后台线程。
2. 线程切换的实现原理
EventBus 通过以下机制实现线程调度:
(1) 主线程切换(MAIN/MAIN_ORDERED)
核心类:HandlerPoster(内部封装 Handler)
实现逻辑:
通过Looper.getMainLooper() 获取主线程的 Looper。
使用 Handler 将事件投递到主线程的 MessageQueue。
主线程的 Handler 收到消息后,执行订阅方法。
// HandlerPoster.java(EventBus 源码)
final class HandlerPoster extends Handler {
@Override
public void handleMessage(Message msg) {
// 在主线程执行订阅方法
PendingPost pendingPost = (PendingPost) msg.obj;
eventBus.invokeSubscriber(pendingPost);
}
}
(2) 后台线程切换(BACKGROUND/ASYNC)
核心类:BackgroundPoster(BACKGROUND)、AsyncPoster(ASYNC)
实现逻辑:
BACKGROUND:使用 单线程线程池,保证事件顺序执行。
ASYNC:使用 可扩容线程池(如 Executors.newCachedThreadPool()),支持并发执行。
// BackgroundPoster.java(EventBus 源码)
final class BackgroundPoster implements Runnable {
private final PendingPostQueue queue;
private final EventBus eventBus;
@Override
public void run() {
// 在后台线程执行订阅方法
PendingPost pendingPost = queue.poll();
eventBus.invokeSubscriber(pendingPost);
}
}
3. 事件处理流程
以下是事件发布到订阅方法执行的完整流程:
1. 发布事件:eventBus.post(event)
2. 查找订阅者:遍历所有注册的订阅方法,匹配事件类型。
3. 线程调度:
- 根据 @Subscribe(threadMode) 确定目标线程。
- 将事件封装为 PendingPost,投递到对应队列:
- MAIN → HandlerPoster
- BACKGROUND → BackgroundPoster
- ASYNC → AsyncPoster
4. 线程切换:
- 主线程:通过 Handler 发送消息到主线程 MessageQueue。
- 后台线程:通过线程池执行任务。
5. 执行订阅方法:在目标线程调用 subscriberMethod.method.invoke(subscriber, event)。
4. 关键源码解析
(1) 事件投递逻辑
// EventBus.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 BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
}
}
(2) 主线程投递器(HandlerPoster)
// HandlerPoster.java
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
// 发送消息到主线程
sendMessage(obtainMessage());
}
}
}
5. 使用示例
(1) 订阅方法定义
// 在主线程更新 UI
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
textView.setText(event.text);
}
// 在后台线程处理数据
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void saveToDatabase(DatabaseEvent event) {
database.insert(event.data);
}
// 在异步线程执行网络请求
@Subscribe(threadMode = ThreadMode.ASYNC)
public void fetchData(NetworkRequestEvent event) {
String result = networkClient.request(event.url);
eventBus.post(new NetworkResponseEvent(result));
}
(2) 注意事项
避免内存泄漏:在组件销毁时反注册订阅者(如 onDestroy() 中调用 unregister())。
线程安全:在 BACKGROUND 或 ASYNC 模式中操作共享数据时,需加锁或使用线程安全数据结构。
性能优化:频繁事件建议使用 POSTING 模式减少线程切换开销。
6. 总结
EventBus 通过 线程模式注解 + Handler/线程池 实现跨线程事件分发。
MAIN 模式依赖主线程 Handler,BACKGROUND/ASYNC 模式使用不同线程池策略。
合理选择线程模式可优化性能并避免线程安全问题。