跪拜 Guibai
← All articles
Android · Android Studio

EventBus Went From Android Standard to Pariah — and It's Not the Library's Fault

By 程序员_小雨 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

A library that was once in nearly every Android project is now being systematically removed. The shift isn't about bugs — it's about architecture maturity: implicit event buses trade short-term wiring speed for long-term maintenance debt, and the modern Android stack now offers state-observation patterns that give you the same decoupling without the untraceable side effects.

Summary

greenrobot's EventBus once dominated Android development because it replaced layers of callbacks, broadcasts, and manual context-casting with a single post-and-subscribe pattern. A `post(new LoginSuccessEvent())` and a handful of `@Subscribe` methods were all it took to wire up a dozen pages. That simplicity was revolutionary when the alternative was deep interface chains and LocalBroadcastManager boilerplate.

The same qualities that made it popular turned toxic at scale. Implicit dependencies mean a `post()` call reveals nothing about what will execute — you must grep the entire codebase for every subscriber. Call chains break at the event boundary, so debugging a login-triggered UI stall requires manually hunting through every listener. On Android specifically, EventBus ignores component lifecycles; forgetting an `unregister` leaks Activities and causes crashes when destroyed pages try to update UI. Thread-mode annotations scatter execution across POSTING, MAIN, BACKGROUND, and ASYNC threads with no visibility into which subscriber runs where.

Modern Android architecture — ViewModel, StateFlow, Lifecycle — replaces the broadcast mindset with a state mindset. A `MutableStateFlow<UserState>` observed by UI layers makes dependencies explicit, call chains traceable, and lifecycle handling automatic. EventBus still fits genuinely global broadcasts like forced logout or theme switching, but for ordinary state-driven UI updates it has become a liability that teams are actively ripping out.

Takeaways
EventBus replaced deep callback chains and manual broadcasts with a one-line post and annotated subscribers, which is why it spread so fast in early Android.
Implicit dependencies are the core problem: a `post()` call reveals nothing about which subscribers will fire, forcing global searches to understand impact.
Call chains break at the event boundary, making debugging a matter of manually hunting every `@Subscribe` method rather than following a stack trace.
EventBus does not respect Android component lifecycles; developers must manually register/unregister, and forgetting to unregister causes memory leaks and crashes on destroyed pages.
Thread-mode annotations (POSTING, MAIN, BACKGROUND, ASYNC) scatter execution across threads with no central visibility, multiplying debugging difficulty.
Modern Android architecture uses state observation (ViewModel + StateFlow/LiveData) instead of event broadcasting, making dependencies explicit and lifecycle-safe.
EventBus still fits truly global broadcasts — forced logout, language switch, theme change — and communication in highly modularized or plugin-based systems.
Most business scenarios like refreshing a profile after an avatar change are state changes, not one-off events, and belong in a Repository observed through ViewModels.
Conclusions

EventBus's decline is a case study in how a library's core value proposition — unrestricted communication freedom — becomes its fatal flaw when codebases and teams grow beyond a certain size.

The Android ecosystem's architectural maturation (ViewModel, StateFlow, Lifecycle) didn't just offer alternatives; it made the entire broadcast paradigm feel like technical debt because state observation provides the same decoupling with full traceability.

The phrase 'event hell' describes a real organizational failure mode: when posting an event becomes the default answer to any cross-component need, the event catalog grows into an unmaintainable, untouchable tangle that nobody fully understands.

EventBus's threading model illustrates a broader design tension — annotation-driven thread selection looks convenient in small examples but becomes a distributed concurrency nightmare when dozens of subscribers choose different execution contexts for the same event.

Concepts & terms
Implicit dependency
A dependency between components that exists at runtime but is not visible in the source code's import or reference graph. With EventBus, a sender and its subscribers have no direct code references, so the connection is invisible to static analysis and to a developer reading the posting site.
Event hell
The state of a codebase where events have proliferated unchecked — dozens or hundreds of event types, many with unclear purpose or unknown subscribers — making the event bus an untouchable tangle that nobody dares to refactor.
Broadcast mindset vs. state mindset
Broadcast mindset treats occurrences as one-off notifications ('login succeeded, tell everyone'). State mindset treats them as persistent state changes ('the user is now logged in') that UI layers observe and render reactively. The latter makes dependencies and update chains explicit.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗