跪拜 Guibai
← Back to the summary

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

Anyone who has done Android development for a few years has probably had a "this is great" moment with EventBus. In Android projects a few years ago, greenrobot's EventBus was practically standard equipment; whenever cross-component messaging came up, the first instinct was to pull it out.

But the industry's attitude has long since reversed: new projects basically don't introduce it, old projects are busy refactoring to remove it, and it has gradually become the poster child for "outdated, full of pitfalls, not recommended."

Many people wonder: EventBus itself hasn't had major bugs, its functionality hasn't degraded — so why is it suddenly being shunned?

1. Why did EventBus become standard equipment for Android back then?

To understand its popularity, you have to know how painful cross-component communication was in early Android development.

Activity, Fragment, Service, BroadcastReceiver — each has its own lifecycle and its own launch rules, yet business logic always requires passing messages across components. Take the most common login scenario: after a user logs in successfully, the home page needs to refresh data, the profile center needs to update info, the shopping cart needs to refresh its state, the messages page needs to update its badge count… Sending all those notifications could make you sick of writing code.

Without EventBus, you were stuck with a few clumsy approaches:

That's when EventBus burst onto the scene.

One line to post an event:

EventBus.getDefault().post(new LoginSuccessEvent());

Wherever needed, add an annotated subscriber:

@Subscribe
public void onLoginSuccess(LoginSuccessEvent event) {
    refresh();
}

Done.

The sender doesn't need to know who will receive it; the receiver doesn't need to know who sent it. Everything is routed through EventBus in the middle. Decoupled, concise, quick to pick up — a few lines of code could replace dozens of lines of work from before. For a development environment full of callbacks and tight coupling at the time, the experience was a quantum leap. No wonder it quickly swept through the entire Android world and became a must-have dependency for projects large and small.

2. The pitfalls were discovered gradually: implicit dependencies are the biggest landmine

When a project is small, using it feels great no matter what. Once the codebase grows and the team expands, problems emerge one after another.

The first and foremost is implicit dependencies.

You take over an old project and see a line EventBus.getDefault().post(new LoginSuccessEvent()). You want to know what operations this line of code will trigger? Sorry, the code shows you absolutely nothing. You have to globally search for the LoginSuccessEvent class, then comb through every method annotated with @Subscribe to finally understand that seven or eight pages and modules are all listening for this event.

On the surface of the code, LoginManager and HomeFragment, MineFragment have no dependency relationship, but in reality they are tightly bound together through EventBus. This kind of dependency that "exists but is invisible" is a maintenance nightmare for large projects — you change one event and can't predict how many places will be affected; you delete one subscriber and don't know whether some logic will be missed.

More headache-inducing than implicit dependencies is that the call chain is completely untraceable.

For example, a bug appears: after a user logs in successfully, the home page suddenly starts lagging. You trace down the login method, reach a line that posts an event, and the trail simply breaks. What logic was actually triggered afterward? Which step caused the lag? You simply can't follow the call stack downward; you have to dig through subscriber after subscriber.

Normal code logic is A→B→C→D, the chain is clear, set a breakpoint and you can follow it to the end. With EventBus it becomes A posts an event, then a bunch of subscribers sitting who-knows-where each execute on their own — the entire call chain shatters into fragments. In large projects with hundreds or thousands of events, troubleshooting efficiency can drop to a maddening low.

3. A fatal flaw unique to the Android platform: uncontrolled lifecycle

On the Android platform, EventBus has an unavoidable native problem: it completely ignores component lifecycles.

Android's Activity and Fragment can be destroyed at any moment, but EventBus itself doesn't perceive this. You have to register in onStart and unregister in onStop yourself; miss one step and you've stepped on a landmine.

Forgot to unregister? EventBus will keep holding a reference to the Activity, the garbage collector can't reclaim it — direct memory leak. Even worse, the page is already destroyed, yet when an event arrives it still tries to execute UI updates, and it crashes on you directly.

Developers not only have to manage business logic but also personally keep an eye on registration, unregistration, lifecycle, and thread switching. A moment's carelessness and you step on a pitfall. When the project is small you can still rely on discipline and conventions; once there are more people and the code gets messy, problems are just a matter of time.

Then there are threading issues — they look convenient but are actually chaotic. EventBus provides several thread modes: POSTING, MAIN, BACKGROUND, ASYNC. One annotation can specify the execution thread. But when the project grows large, chaos ensues: for the same event, some subscribers switch to the main thread, some to a background thread, some execute directly on the posting thread.

When problems like UI lag, data races, or duplicate execution arise, you simply cannot tell at a glance which thread this logic is actually running on — troubleshooting complexity doubles instantly.

4. It's not that EventBus got worse; the development mindset changed

To be fair, it's not that EventBus got worse, but that the entire approach to Android development changed.

In early Android development, everyone was still in the exploratory phase — whatever was convenient went, and being able to implement features quickly was king. But as projects grew larger and teams bigger, the industry began pursuing maintainability, traceability, and controllability. Google also gradually released a complete set of architecture components: ViewModel, LiveData, StateFlow, Lifecycle… The unidirectional data flow approach gradually became mainstream.

EventBus is a classic broadcast mindset: login succeeded, post an event to tell everyone, and everyone who receives it does whatever they need to do. Modern Android architecture, by contrast, is a state mindset: the user's login state has changed to logged-in; each UI layer observes this state and automatically renders the corresponding interface.

A single word difference, worlds apart.

Take StateFlow as an example. Maintain a user state in the ViewModel:

class UserViewModel : ViewModel() {
    private val _userState = MutableStateFlow<UserState>(UserState.Loading)
    val userState = _userState.asStateFlow()
}

The UI layer subscribes directly:

lifecycleScope.launch {
    viewModel.userState.collect { state ->
        render(state)
    }
}

Who holds the state, who observes the state, what logic a state change will trigger — all clear at a glance. Dependency relationships are explicitly written in the code, the call chain is clear and traceable, and it comes with built-in lifecycle awareness: when the page is destroyed, the subscription stops automatically — no leaks, no crashes.

All of EventBus's advantages are replaced here; and all of EventBus's pitfalls are absent here.

Worse still, overusing EventBus easily leads to "event hell." When a project just starts, there are only a few events — LoginEvent, LogoutEvent, RefreshEvent — clean and tidy. But as the business iterates, today you add an avatar update event, tomorrow a shopping cart change event, the day after a global config change event… Half a year later, the project is stuffed with dozens or even hundreds of Event classes; every piece of logic wants to be solved by posting an event.

In the end EventBus becomes a "garbage communication bus": whenever anyone encounters a cross-component problem, they post an event and toss it out. As for who receives it, how it's handled, whether there are duplicates — no one can say clearly. Many events, in the end, no one knows why they exist or whether anyone still uses them, and no one dares to touch them.

5. Is EventBus really completely unusable now?

Of course not. It's just unsuitable for writing ordinary business logic, not worthless.

For example, truly global broadcast scenarios: forcing an app-wide logout, global language switching, dark mode switching… These are inherently "one event occurs, multiple modules may care" scenarios, and EventBus's model is actually quite fitting.

Similarly, in plugin-based or highly modularized systems where modules don't want direct dependencies, using events as a communication protocol is also a reasonable choice.

But for the vast majority of business scenarios — such as refreshing the profile center after changing an avatar, refreshing the shopping cart after placing an order — really stop using EventBus. These are essentially "data state has changed" rather than "a one-time event occurred." Centralize the state in a Repository, have each page observe the state through a ViewModel and update automatically — far more reliable than firing off a bunch of events.

6. A final honest word

EventBus rose because it solved the pain point of Android component communication back then, achieving decoupling in the simplest way possible — it was an excellent solution for its era.

It is being shunned not because it did anything wrong, but because its greatest strength — unfettered communication freedom — ultimately became its greatest weakness in large-scale engineering: anyone can post, anyone can receive, and in the end no one can say clearly who is communicating with whom.

Android architecture's evolution over all these years is really the process of moving from "pursuing development efficiency" to "pursuing maintenance efficiency." From convenience to controllability, from flexibility to standardization — EventBus's rise and fall is precisely the most authentic缩影 of this process.

Comments

Top 1 from juejin.cn, machine-translated. The original thread is authoritative.

dora

Now using RxBus.