Android From Scratch: Understanding Android Broadcasts

Most of us are all too familiar with announcements in public places. They are loud messages that are meant to inform large groups of people about something important. Android applications also have to deal with announcements sometimes—announcements generated either by other applications or by the Android operating system itself. Such announcements are called broadcasts, and they are seen as an important form of asynchronous inter-process communication on the Android platform.

In this tutorial, I'll show you how to create, send and receive both local and system-wide broadcasts. I'll also show you how to use a third-party library called EventBus that can serve as an alternative to local broadcasts.

1. Creating a Broadcast

Android broadcasts are sent in the form of Intent objects. Therefore, before you create a broadcast, you must create an Intent object. This series has a detailed tutorial about intents. If you haven't read it yet, now would be a good time to do so.

Every intent you send as a broadcast must have an action name. Although the action name can be any string, I recommend that you always prefix it with the package name of your app in order to avoid conflicts with broadcasts of other applications.

The follow code snippet shows you how to create a new intent whose action name is com.tutsplus.my.first.broadcast:

To send the intent as a broadcast, all you need to do is call the sendBroadcast() method and pass the Intent object as an argument to it.

Note that the sendBroadcast() method creates a global broadcast that can be received by not only your application but also any other application installed on the user's device.

2. Receiving Broadcasts

To be able to receive a broadcast, your application must have an appropriately configured broadcast receiver. You can create a broadcast receiver by extending the BroadcastReceiver abstract class and overriding its onReceive() method. For example, here's how you create a broadcast receiver that prints a message every time it receives a broadcast:

A broadcast receiver works only if it is registered. The easiest way to do so is to declare it in the project's manifest file using a receiver tag.

Additionally, inside the declaration of a broadcast receiver, you must include intent-filter tags that specify the action names the broadcast receiver is interested in.

The following code snippet registers MyBroadcastReceiver and configures it to respond to an action called com.tutsplus.my.first.broadcast:

3. Receiving System Broadcasts

The Android operating system issues several global broadcasts. Most of them contain valuable information about changes in the Android device's state. For example, every time a user places a new outgoing call, the android.intent.action.NEW_OUTGOING_CALL broadcast is issued. Similarly, every time a user turns airplane mode on or off, the android.intent.action.AIRPLANE_MODE broadcast is issued.

Receiving system broadcasts is just like receiving ordinary broadcasts. Most system broadcast intents, however, contain additional information in the form of extras. You can fetch all those extras as a Bundle object by calling the getExtras() method. For example, the android.intent.action.AIRPLANE_MODE broadcast intent always contains an extra called state, which is a boolean specifying whether airplane mode has been turned on or off.

The following code snippet shows you how to log the value of the state extra:

Note that the above code will work only if the broadcast receiver has been registered with the following intent filter:

4. Working With Local Broadcasts

For obvious reasons, global broadcasts must never contain sensitive information. You can, however, broadcast such information locally using the LocalBroadcastManager class, which is a part of the Android Support Library.

If you are using the latest version of Android Studio, you won't have to manually add a dependency for the Android Support Library. However, if you want to implement local broadcasts in an old project, make sure that the following line is present in the app module's build.gradle file:

To create a new instance of the LocalBroadcastManager class, you must call its getInstance() method and pass your activity or service as its context. For example, here's how you would create the instance inside an activity called MyActivity:

You can now send local broadcasts using the sendBroadcast() method of the LocalBroadcastManager class. The following code snippet creates a new intent, whose action name is my-local-broadcast, and sends it as a local broadcast:

Receiving a local broadcast is slightly more involved. A local broadcast receiver must not be registered in the project's manifest file. Instead, it must be registered dynamically using the registerReceiver() method of the LocalBroadcastManager class. In addition to a broadcast receiver instance, the registerReceiver() method requires an IntentFilter object specifying the action name the broadcast receiver should respond to.

Here's how you would create and register a broadcast receiver that can respond to the my-local-broadcast action:

Dynamically registered receivers must be unregistered when they are no longer necessary. To do so, you must use the unregisterReceiver() method of the LocalBroadcastManager class.

5. Using EventBus

If you think local broadcasts and intents don't give you all the flexibility you need, you should consider using EventBus, a third-party library that allows you to asynchronously send data from one component of your application to another. In my opinion, the EventBus API is very intuitive and succinct.

To include EventBus in your project, add the following compile dependency to your app module's build.gradle file:

Instead of just Intent objects, EventBus allows you to send and receive objects of any Java class. For example, instances of the following class can be easily used with EventBus:

EventBus implements the publisher-subscriber pattern and creates a central bus that is accessible to all the components of your application. Therefore, a component that needs to send objects must simply publish the objects on the bus. A component that is interested in receiving those objects must register itself as a subscriber of the bus.

The quickest way to fetch an instance of the central bus is to use the getDefault() method of the EventBus class.

To publish an object, all you need to do is call the post() method of the bus. For example, here's how you would publish an instance of the MyMessage class:

An app component, such as an activity or service, can register itself as a subscriber by calling the register() method of the bus. The following sample code registers a service called MyService:

A component that is acting as a subscriber must also have a subscriber method, which is any method that has the @Subscribe annotation. Subscriber methods behave much like event handlers and are automatically called every time new objects are available on the bus.

The following code snippet shows you how to create a very simple subscriber method that is automatically called every time a new instance of the MyMessage class is available on the bus:

Conclusion

In this tutorial, you learned how to send information from one application component to another using both global and local broadcasts. You also learned how to use the very popular EventBus library for intra-app communication. Because broadcasts have a very low overhead, you are free to send them as often as necessary. In fact, the Android system generates a new android.intent.action.TIME_TICK broadcast every single minute.

To learn more about Android broadcast receivers and broadcasts, you can refer to the documentation of the BroadcastReceiver and Intent classes.

Tags:

Comments

Related Articles