eventbus适用于同进程内松耦合模块通信,需遵循轻注册、明事件、控线程三原则,规避内存泄漏与线程混乱,禁用于强生命周期依赖、需返回值、高频实时同步及跨进程场景。

在复杂老旧项目中用 EventBus 实现跨模块通信,核心不是“能不能用”,而是“怎么用得稳、不埋雷”。它本质是进程内发布-订阅机制,不依赖中间件、不跨进程,适合模块间松耦合通知,比如 Fragment 切换后刷新列表、Service 完成任务后通知 UI、Native 与 WebView 交互等场景。但老旧项目往往存在注册遗漏、线程混乱、事件泛滥等问题,需针对性控制。
明确 EventBus 的适用边界
它解决的是同进程内、非父子关系、无直接引用的模块通信。不适合以下情况:
- 模块有强生命周期依赖(如 A 必须等 B 初始化完才能发消息)——应改用接口契约或依赖注入
- 需要返回值或阻塞等待响应——EventBus 是单向广播,不支持回调结果
- 高频小数据实时同步(如传感器数据流)——建议用 LiveData 或 Flow 配合 StateFlow
- 跨进程通信(如插件化、多 APK)——得用 AIDL、Messenger 或 MMKV + 文件监听
老旧项目接入三原则:轻注册、明事件、控线程
避免在 BaseFragment/BaseActivity 全局自动注册,容易引发重复注册或漏反注册。推荐按需、显式、防御式处理:
-
注册只在真正需要监听的地方做:比如某个 Fragment 确实要接收“用户登出”事件,才在
onCreate或onViewCreated中调用EventBus.getDefault().register(this),并加!isRegistered()判断 -
事件类必须独立、不可变、带语义:不要用
String或Map传参,定义清晰的 data class 或 Java Bean,例如OrderStatusChangedEvent(orderId, newStatus),避免后期字段歧义 -
线程模型必须显式指定:老旧项目常混用主线程/子线程更新 UI,务必在
@Subscribe注解里写明threadMode = ThreadMode.MAIN(UI 更新)、ThreadMode.POSTING(同线程快速响应)、ThreadMode.BACKGROUND(耗时操作),禁用默认行为
规避内存泄漏与崩溃风险
老旧项目中最常见问题是 onDestroy 未反注册或注册对象被提前释放:
- Activity/Fragment 在
onDestroy或onDetach中必须调用unregister(this),且建议包一层 try-catch,防止空指针或已注销报错 - 避免在匿名内部类、Lambda、Handler 回调中注册 EventBus(它们持有外部 Activity 引用,易导致泄漏)
- WebView 侧 JS 调用 Android 方法时若注册了 EventBus,需在
onPageFinished后注册、onDestroy前反注册,并检查 WebView 是否已被销毁 - 混淆配置必须保留:确保
-keepclassmembers class * {@org.greenrobot.eventbus.Subscribe <methods>;}</methods>已加入 proguard-rules.pro
模块解耦的实用技巧
在 app、feature、lib_common 等多模块项目中,让通信不依赖具体实现:
- 事件类统一放在
lib_common模块,所有模块都可引用,避免各模块定义同名不同义的 Event - 发送方不 import 接收方,接收方也不 import 发送方,双方只依赖事件类和 EventBus SDK
- 用事件类型区分业务域,例如
ProfileUpdateEvent、PaymentResultEvent、CacheClearedEvent,不用泛化的BaseEvent+ type 字段 - 关键事件可加日志埋点,例如
EventBus.getDefault().post(new DebugEvent("login_success", System.currentTimeMillis())),便于线上问题追溯











