Android事件框架总线对比

2 阅读4分钟

Android 里的"事件总线"现在已经不是一个框架通吃的事了,得按场景拆:EventBus(GreenRobot) ​ 是老牌霸主,LiveData / Kotlin Flow(SharedFlow) ​ 是 Jetpack 时代 Google 主推的替代,RxBus​ 是 RxJava 时代的产物,现在基本被 Flow 取代。下面把主流方案摊开讲。


主流框架一览

1️⃣ EventBus

最经典的事件总线,基于注解 + (默认)反射,3.x 后可用 APT 编译期生成索引把注册耗时从 ~1-5ms 压到 ~0.01ms。

  • 优点:上手极简、一对多广播、跨模块天然解耦、粘性事件原生支持、线程模式(MAIN/POSTING/BACKGROUND/ASYNC)齐全
  • 缺点:不感知生命周期,忘 unregister 就泄漏;事件链路隐式,调试时很难追"谁发的、谁收的";无背压
  • 典型场景:登录/登出广播、全局配置变更、网络状态切换、跨模块无依赖通信

2️⃣ LiveData(Jetpack)

严格说它不是"事件总线",是生命周期感知的状态持有者,但常被拿来替代 EventBus 做组件内通信。

  • 优点:自动感知 Lifecycle,不会在 destroyed 后回调;与 ViewModel 搭配是 Google 官方 MVVM 标配
  • 缺点:天然粘性(新 Observer 会收到上次的值)→ 数据倒灌问题,得用 SingleLiveEvent/ UnPeekLiveData绕;线程只能主线程回调(postValue半自动切);操作符贫弱(map/switchMap就这点)
  • 典型场景:ViewModel → View 的状态驱动(列表数据、Loading 状态等)

3️⃣ Kotlin Flow(SharedFlow / StateFlow)

目前最推荐的新项目方案,协程体系下的响应式流。

维度EventBusLiveDataStateFlow / SharedFlow
生命周期感知❌ 手动✅ 自动repeatOnLifecycle
线程切换✅ ThreadMode仅主线程flowOn+ Dispatcher
粘性✅(天然)StateFlow 粘性,SharedFlow 可配 replay
背压✅ buffer/conflate
操作符⚠️ 极少✅ 丰富
调试追踪❌ 隐式✅ 明确持有者✅ 明确流链路

性能上 Pixel 4 实测每秒 100 次简单事件:EventBus 延迟 ~12ms / CPU 8%,SharedFlow ~9ms / CPU 6%,LiveData 扛不住高频。

  • StateFlow​ ≈ LiveData 替代品(总是持有最新值,冷流)
  • SharedFlow​ ≈ EventBus 替代品(多订阅者、可配 replay、一次性事件用 replay=0 extraBuffer=0

4️⃣ RxBus(RxJava + Subject)

RxJava 时代的自制事件总线(BehaviorSubject / PublishSubject)。

  • 功能最强(操作符全家桶、线程随意切),但体积大、学习曲线陡、易内存泄漏,新项目基本被 Flow 替代,只在存量 RxJava 项目里还能见到。
  • 在Java项目种使用,部分场景下可用CompletableFuture 代替。

EventBus与RxJava对比

如果一个订阅者需要注册多个事件的时候,Rxjava需要一个个单独的注册,而EventBus则可以实现一个订阅者订阅多个事件,和一个事件对应多个订阅者。所以在Rxjava的基础上有了Rxbus来作为事件总线的库。RxBus在订阅者数量很大的情况下性能下降很明显,比不过EventBus。 RxAndroid 可理解为专供Android平台的RxJava,针对平台增加了少量类。

CompletableFuture 与RxJava对比

维度CompletableFutureRxJava
抽象模型一个异步结果(Promise)一个事件流(Stream)
数据量单个值 / 异常0~N 个值 + 完成 / 异常
消费方式一对一一对多
是否可复用❌ 一次性的✅ 可重复订阅
是否支持事件总线❌ 不适合✅ 天生适合
背压❌ 无✅ 有
线程调度基础极其精细

5️⃣ LocalBroadcastManager

已废弃,别用了,反射+Intent 性能差、类型不安全。


选型决策树

💡 一句话原则:能用 Flow/LiveData 就别上 EventBus,EventBus 只留给"跨模块全局广播"这一窄场景

  • 同一页面 / 同一模块内​ View → VM → View → ViewModel + LiveData 或 StateFlow
  • 父子 Fragment 通信​ → Fragment Result API / Navigation SavedStateHandle(不是事件总线)
  • 一次性事件(Toast、导航、Snackbar)→ SharedFlow(replay=0) ​ 或 Channel
  • 跨模块、无依赖、一对多广播(登录态、埋点、配置推送)→ EventBus​ 仍是最省事的解法
  • 高频事件 / 需要背压 / 复杂数据流变换​ → Flow
  • 存量 RxJava 项目​ → RxBus 继续用,新模块切 Flow

一个常见的坑

LiveData 做"事件类"数据(导航、Toast)会数据倒灌——屏幕旋转后 Observer 重新注册,又会收到上次那次导航事件,页面跳两次。解决办法:

  • 老方案:SingleLiveEvent(但只支持一个 Observer,坑)
  • 改进:UnPeekLiveData(允许多 Observer,只消费一次)
  • 彻底解:换 SharedFlowreplay=0,天然单次,没这问题