Skip to content

Communicating with an Event Bus

codepath-wiki-review[bot] edited this page Jun 23, 2026 · 44 revisions

Attention: This guide reflects an older era of Android app architecture. Otto was archived in April 2019, and the third-party greenrobot/EventBus library has had no published releases since 3.3.1 in December 2021. More importantly, Google's current guidance does not treat a global pub/sub bus as the default mechanism for cross-Activity / cross-Fragment communication. The official Communicate with fragments page recommends:

  • A shared ViewModel exposing StateFlow / SharedFlow (or LiveData in existing codebases) for state shared between fragments and their host activity.
  • The Fragment Result API (setFragmentResult / setFragmentResultListener) for one-time Bundle-shaped results between fragments under the same FragmentManager.
  • For Navigation-based flows, returning results to a previous destination via NavBackStackEntry.savedStateHandle (e.g. navController.previousBackStackEntry?.savedStateHandle?.set(...)).

Android's UI events architecture guide reinforces this by explicitly recommending against modelling one-off events through a separate event stream alongside UI state — such events are not guaranteed to be delivered when the consumer is paused. New code should reach for the patterns above unless there is a concrete reason a global bus is a better fit.

The rest of this page is kept as a historical reference for projects already wired up to EventBus. New code should follow the modern guidance linked above.

Background

The Android framework offers several first-party mechanisms for moving data between components:

Earlier-generation Android projects sometimes wrapped these patterns in a global publish/subscribe bus to decouple producers from consumers: publishers post events in response to a state change, and subscribers respond to those events without holding a direct reference to the publisher. This 2012 Square blog post introduced Otto (now archived) as one such bus; greenrobot/EventBus was a contemporary alternative, and reactive libraries like RxJava were sometimes used to build a custom "RxBus" on the same principle.

Modern Android architecture takes a different approach: state is owned by a ViewModel and exposed as an observable stream (StateFlow, SharedFlow, or LiveData), and Fragments and Activities subscribe to that stream rather than to a process-wide bus. The remainder of this page documents how EventBus was wired up in projects that pre-date this architecture, for codebases that still maintain that style — not as a recommendation for new work.

Considerations when maintaining EventBus code

When working in a codebase that already uses an event bus, keep these constraints in mind:

  • A bus is not a drop-in replacement for every form of communication. If an event is meant for a single subscriber and shouldn't trigger changes elsewhere, prefer a direct 1-to-1 channel — an Intent or a listener interface — so the event isn't broadcast to unrelated components. See this article for typical event-bus design patterns.

  • Register and unregister subscribers in lock-step with the lifecycle of the Activity or Fragment that owns them. Holding a subscription past onPause/onDestroy is a common source of memory leaks and crashes from stale references.

  • Events posted while a Fragment is not running may be dropped. If a Fragment publishes an event to another Fragment that isn't currently attached, the event will not necessarily be delivered. EventBus's sticky events feature can re-deliver the most recent value to a new subscriber, but this is a workaround for the fundamental ordering issue — a shared ViewModel exposing a StateFlow solves the same problem more cleanly in new code.

Historical reference: setting up greenrobot EventBus

The snippets below describe setup against greenrobot/EventBus 3.3.1, the project's most recent release (December 2021). They are kept here only as a reference for codebases that already depend on EventBus. For new code, follow the modern guidance in the banner at the top of this page.

Add this Gradle dependency to your app/build.gradle file:

dependencies {
    implementation 'org.greenrobot:eventbus:3.3.1'
}

Historical use case: replacing LocalBroadcastManager

In pre-Architecture-Components codebases, one common motivation for adopting EventBus was to avoid the boilerplate around LocalBroadcastManager (itself deprecated in androidx.localbroadcastmanager 1.1.0-alpha01) when relaying data from a Service to an Activity. Using the bus removed the serialization/deserialization step that Intent extras forced. Today, the recommended modern equivalent is a shared ViewModel (or a repository) exposing a Flow/SharedFlow that the Service writes to and the Activity collects.

Registering on the Bus

If you wish to subscribe Activities and Fragments to the event bus, it should be done with respect to the lifecycle of these objects. The reason is that when an event is published, EventBus will try to find all the registered subscribers. If there is a subscriber attached to the Activity currently not running, there is likely to be a stale reference that causes your app to crash.

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onPause() {
        super.onPause();
        EventBus.getDefault().unregister(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        EventBus.getDefault().register(this);
    }
}

Creating an Event

Create a new Event from a standard Java class. You can define any set of members variables. For now, we create a class to accept a result code and a String values.

public class IntentServiceResult {

    int mResult;
    String mResultValue;

    IntentServiceResult(int resultCode, String resultValue) {
        mResult = resultCode;
        mResultValue = resultValue;
    }

    public int getResult() {
        return mResult;
    }

    public String getResultValue() {
        return mResultValue;
    }
}

Creating a publisher

Inside our Intent service, we can should publish the event. We will simply pass an OK result with a message that will be displayed when the event is received on the Activity.

@Override
protected void onHandleIntent(Intent intent) {

    // do some work
    EventBus.getDefault().post(new IntentServiceResult(Activity.RESULT_OK, "done!!"));
}

Creating a subscriber

We simply need to annotate a method that has this specific event type with the @Subscribe decorator. The method must also take in the parameter of the event for which it is listening. In this case, it's IntentServiceResult.

Because the IntentService is executed on a separate thread, the subscribers will normally also execute on the same thread. If we need to make UI changes on the main thread, we need to be explicit that the actions executed should be done on the main thread. See this section for more information.

public class MainActivity extends AppCompatActivity {

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void doThis(IntentServiceResult intentServiceResult) {
        Toast.makeText(this, intentServiceResult.getResultValue(), Toast.LENGTH_SHORT).show();
    }
}

References

Finding these guides helpful?

We need help from the broader community to improve these guides, add new topics and keep the topics up-to-date. See our contribution guidelines here and our topic issues list for great ways to help out.

Check these same guides through our standalone viewer for a better browsing experience and an improved search. Follow us on twitter @codepath for access to more useful Android development resources.

Clone this wiki locally