When developing Android apps, it’s often necessary to establish some kind of communication between various framework components such as Activity, Fragment, Service or AsyncTask. These components all have their own life cycles and are weakly connected to each other, making the communication between them a bit tricky.

Drawbacks of standard approach

One standard approach for establishing communication between all these components involves creating special interfaces, known as listeners. Any class can pass a listener instance to any component, that will take care of notifying the listener about various events happening inside that component.

This approach has two main weaknesses:

Components don't always know about each other and may not be able to pass and receive listener objects directly. If a user changes some data on screen (like his name), we need to update the data on the other applications screens. But an Activity or Fragment cannot talk to each other due to Android platform limitations, so we cannot pass the listener from one activity to another.

Any non-trivial application with many interlinked components will require implementing a lot of listeners. This will most likely complicate your code and make it less flexible and highly cohesive.

Efficient solution: A message bus

A well-established approach to this problem is a message bus (as described by the publish-subscribe pattern). This approach is widely used in the Android platform itself, e.g. in the implementation of Intents.

A message bus works as follows: any component, that would like to receive notifications from other parts of the application, registers within the bus (subscribes to event notifications). When an event is fired, a message is sent (published) to the bus, and is immediately forwarded to all the registered subscribers. The components don't have to talk to each other directly.

A bus may also have the ability to create so-called sticky events which persist in the bus and are constantly delivered to all new subscribers (and existing subscribers when first published). Sticky events are typically overwritten if a sticky event of the same type is already present in the bus when a newer event is published. They're commonly used when we don't want the subscriber to miss an important event such as loading data over the network or when we want the subscriber to receive messages immediately upon registration without waiting for a new non-sticky event.

Examples of using message buses

Let's take a look at a couple of examples of using message buses in applications.

1. Loading and displaying news feeds

Suppose we develop an application with main menu using Navigation Drawer. One of the screens accessible from the menu is a Fragment with the news feed and the number of unread items is displayed in the menu.

The application is made of 4 major components: a menu, a fragment to display the news, a local DB and an AsyncTask that loads news in the background and caches them in the database.

We can construct this application using a message bus. After the application boots, the menu immediately displays the number of unread items in the cache and a task for downloading feed from the server is started in the background.

As soon as the task is successfully completed and the updated feed is stored in the database, a message is published in the bus. The menu and the news fragment receive the message and update themselves according to the new data loaded from the database. Thus, we can get along with less cohesion, because the only shared component here is the database.

2. File download status

Consider a case when the user starts downloading a file from the web (a document or a database update). Downloading the file can take some time and in the meantime the user can leave the screen and come back later. We need to decouple the application UI from the downloading process here and using a file download service is an obvious solution here. However, we still need to report the download status to the user.

In this case we need to establish communication between 2 components: the Activity (GUI) and the downloading service.

Message bus works well for this kind of integration. The service is going to publish sticky events with the current download status (download is active, download progress, file properties). As soon as the information screen (activity) is brought up, it can get all the information it needs from the bus and display it to the user.

How to write a message bus

A message bus can be implemented in a number of ways.

One possible implementation is provided by the Android platform itself. In Android communication, we can use broadcast receivers (defined as subclasses of BroadcastReceiver) to receive messages from other components inside the application. To register a broadcast receiver, add the following code to your Activity:

public class MyActivity extends Activity { private MyReceiver mReceiver; onResume() { // ... IntentFilter filter = new IntentFilter("com.example.MyEvent"); mReceiver = new MyReceiver(); registerReceiver(receiver, filter); } onPause() { // ... unregisterReceiver(mReceiver); } public class MyReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Toast.makeText(context, "MyEvent", Toast.LENGTH_LONG).show(); } } }

And to send a message from some other part of the program use the following code:

public void sendBroadcast() { Intent intent = new Intent("com.example.MyEvent"); intent.putExtra("myParam", "Hello"); sendBroadcast(intent); }

As you see, using BroadcastReceiver for this task requires a lot of code. The more elegant solution is to use one of the open libraries: