It’s 21st century — Stop using EVENTBUS!

Do you still use it!? Have you used it? I mean the EventBus. If the answer is NO, then you are either a new developer who started Android recently or you had the wonderful opportunity to not meet this three-headed monster. What I am talking about? Let’s make a brieft visit of the Android development history.

Android Development History

I will skip some of the periods in the Android app development as I don’t remember exactly how things escalated from one thing to another.

public void onResume() {
Ion.with(getActivity())
.execute("http://whatever.shitty.endpoint")
.(new Callback() {
if (!isAdded()) {
return;
}
// Do whatever
});
}
  • You have tight coupling between Activity/Fragment and your network layer
  • This makes your code practically untestable for unit tests
  • Google was quiet as shit. There was one lecture about application architecture and it was so complicated that noone would bother using it
  • Volley was introduced to solve the problem. But it required so much boilerplate for a single request that it made the problem bigger and not easier. I was a fan of it. Then I stopped being lame and moved to Retrofit.
  • People were still making AsyncTasks that execute requests with custom Http clients. Why bother using something custom when it creates “a ton of shit” and we can create our own shit!?

EventBus to the rescue

The first EventBus library made specially for Android was Otto. It made a huge impact on the poor Android developers that were struggling between Services, Loaders and a very complicated lifecycle management. It made a huge impact on me. And there was the idea that:

EventBus Life Saver

You have this central shared object which is of type EventBus. You can use it to post events on it. Every class can listen for a specific type of event that is posted on this event bus. That’s all. Simple and straightforward.

// MyActivity

@Override
public void onCreate(SavedInstanceState state) {
toolbar.setNavigationOnClickListener(() -> {
ApiService.getInstance().loadAppDetails();
});
}

@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
BusProvider.getInstance().register(this);
}

@Override
public void onDetach() {
super.onDetach();
BusProvider.getInstance().unregister(this);
}

@Subscribe
public void onAppDetailsLoaded(LoadAppDetailsApiEvent event) {
populateAppDetails(event.getBaseApp());
}
  • When the request is done it posts an event on the EventBus of type LoadAppDetailsApiEvent that contains the data
  • If the Activity is not destroyed, it will receive the event from the bus
  • Otherwise, it will be unregistered and it won’t receive the event
  • You have “loose” coupling between you components. They can work separately. You move the networking logic to another class, UI listens for events.
  • You can have multiple components listen for the same event that happens. So if you have a button as a custom view and press it, all the instances of that button will be updated too when the event is posted.
  • You could even get bigger separation in your classes. You could post an event like “GetAppsApiEvent” to which the ApiService listens and then posts “AppsLoadedApiEvent” to which the fragment listens.
  • And it even allowed you to post events between threads. You do code like:
// This now magically works passing events between multiple threads
// You could post event from Service and receive it in the UI
Bus eventBus = new Bus(ThreadEnforcer.ANY);

Event Everything

I had the close opportunity to start an app from scratch, grow it a lot and see how this approach does not work. Here is the result. Do you see how many UI events are there? How many API ones? It is crazy, right? Well, when we started it, it sounded like a good idea. An app based on events with separate classes listening to them. But how separate are the classes? Do they allow you to test them? How about in terms of unit tests? Let’s see why this approach is very very bad.

Bye Unit Tests

It is very hard to mock the event bus. And if you have it as a part of your networking or whatever components, it is quite impossible to test them following the unit test manner. You could do integration testing but what time would it take you to do it? And how would you detect if a problem occurs, in which code layer exactly it happened?

Hello Hours Spent on Onboarding New Dev

Imagine a new developer joins. Imagine you join a project with 50 events, some UI, some API and you need to find where these events are posted and where they are received. You will need your Sherlock Holmes skills with you because it will take you some days.

Welcome Reflection

Now the event buses use compile time annotations. Then, they were using reflection. Althought the impact wasn’t huge, it was there and it was not cool. You cannot depend on reflection to work on different devices.

Freedom to Write Shit

It just allows you to write shitty code. Why should you pass data through bundles when you can post an event with it? Why should you call the APIService when you can post an event to it to it to load data? Why do you need interfaces and callbacks and things like setTargetFragment() when events can do this with several lines of code?

Let’s Close the Page

The cool thing about event bus approach in Android was that at first sight it offered flexibility and “loose” coupling with the price of only adding a single library and nothing more. It looked so perfect, such a lust to developers, you could get an app with “real-time” updates in no time. Just post an event. Most developers would close their eyes to the growing count of useless classes.

Making things happen