Android Broadcast Receivers: A Beginner‘s Guide
As an Android developer, you‘ll often need your apps to respond to events originating from outside the app itself, such as changes to device connectivity, battery level, or timezone. Broadcast receivers provide a flexible mechanism for your app components to listen for and react to these system-wide events.
In this beginner‘s guide, we‘ll cover everything you need to know to start leveraging the power of broadcast receivers in your Android apps. You‘ll learn what broadcast receivers are, how to register them, how to create your own custom receiver classes, best practices to keep in mind, and alternatives to consider. Let‘s dive in!
What are Broadcast Receivers?
A broadcast receiver is a component that allows your app to receive intents that are broadcast by the Android system or other apps, even when your app isn‘t currently running. You can think of broadcasts as system-wide messages notifying apps of events they may be interested in.
There are two main types of broadcasts:
- System broadcasts sent by the Android OS to notify apps of system events (e.g. device boot completed, battery low, etc.)
- App-specific broadcasts sent by apps to notify other components of app-specific events.
Broadcast receivers act as mailboxes that the system or apps can drop messages into. Your app can register a receiver to listen for specific broadcast intents. When a matching intent is broadcast, the system automatically routes it to your app‘s registered receiver.
Registering Broadcast Receivers
There are two ways you can register a broadcast receiver in your app:
1. Declaring in AndroidManifest.xml
You can statically register a broadcast receiver by declaring it in your app manifest using the <receiver> tag:
<receiver
android:name=".MyBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
The android:name
attribute specifies the class name of your broadcast receiver. The android:exported
attribute indicates whether the receiver can receive broadcasts from outside your app.
Inside the <receiver> tag, you specify <intent-filter> tags to define the broadcast actions your receiver subscribes to. The example above listens for the BOOT_COMPLETED
system broadcast.
2. Registering Dynamically
You can also register and unregister receivers dynamically at runtime using the Context.registerReceiver()
and unregisterReceiver()
methods:
val receiver = MyBroadcastReceiver()
// Register receiver
val filter = IntentFilter().apply {
addAction(ConnectivityManager.CONNECTIVITY_ACTION)
addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED)
}
registerReceiver(receiver, filter)
// Unregister when no longer needed
unregisterReceiver(receiver)
With this approach, your receiver will only receive broadcasts as long as it‘s registered. It‘s important to always unregister the receiver when it‘s no longer needed to avoid leaking memory.
Creating a Custom BroadcastReceiver
To create your own broadcast receiver, extend the BroadcastReceiver
class and override its onReceive()
method:
class MyBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Handle received broadcast
val action = intent.action
Log.d("MyBroadcastReceiver", "Received action: $action")
when (action) {
ConnectivityManager.CONNECTIVITY_ACTION -> {
val noConnectivity = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false
)
if (!noConnectivity) {
// Connectivity restored, react accordingly
}
}
// Handle other actions...
}
}
}
The onReceive()
method is called by the system when an intent matching one of your registered intent filters is broadcast. This is where you define how your app reacts to the received broadcast.
The method provides access to a Context
object representing the application context, and an Intent
object containing information about the received broadcast.
It‘s important to keep onReceive()
implementations short and fast, as the method executes on your app‘s main thread. If you need to perform long running operations, start a background service instead.
Broadcasting Events in Your App
In addition to receiving system broadcasts, you can use broadcast receivers for communication between components within your own app.
To send a broadcast intent, you use one of the following Context
methods:
-
sendOrderedBroadcast()
: Delivers the intent to one registered receiver at a time, in priority order. Receivers can propagate results to subsequent receivers. -
sendBroadcast()
: Delivers the intent to all registered receivers simultaneously, with no priority and no mechanism for propagation or results. -
LocalBroadcastManager.sendBroadcast()
: Similar tosendBroadcast()
but the broadcast stays within your app and isn‘t visible to other apps.
For example, to broadcast a custom action indicating that a file has finished downloading in your app:
val intent = Intent("com.example.FILE_DOWNLOADED")
intent.putExtra("fileUrl", downloadedFileUrl)
sendBroadcast(intent)
Components in your app that have registered to receive the com.example.FILE_DOWNLOADED
action will have their onReceive()
method triggered, passing along the downloaded file URL in the intent extras.
Gotchas and Limitations
When working with broadcast receivers, there are some gotchas and limitations to keep in mind, especially in more recent versions of Android.
Firstly, avoid broadcasting sensitive data using implicit intents, as any app with a matching receiver will be able to access that data. Use permissions to limit access or consider explicit intents instead.
Secondly, think twice before starting an activity directly from a broadcast receiver. The resulting user experience is often jarring. Instead, consider showing a notification that then launches the relevant activity when tapped.
Android has introduced incremental limitations on broadcast receivers over the years to improve performance and battery life:
-
Android 7.0: Disables certain system broadcasts like
ACTION_NEW_PICTURE
andACTION_NEW_VIDEO
for manifest-declared receivers. -
Android 8.0: Requires most implicit broadcasts to be registered dynamically, with only a whitelisted set allowed in the manifest.
-
Android 9.0: Provides less information in certain Wi-Fi and network state broadcasts for privacy reasons.
Be sure to check the documentation for the Android version you‘re targeting to understand what restrictions may apply.
Alternatives to Broadcast Receivers
While broadcast receivers are a powerful tool, they may not always be the best solution. Here are a couple alternatives to consider:
-
LocalBroadcastManager
: If your broadcasts are internal to your app, useLocalBroadcastManager
to avoid system overhead and unintended interactions with other apps. -
JobScheduler
: For deferrable background tasks that don‘t need to run immediately,JobScheduler
provides a battery-efficient API to schedule jobs based on criteria like network availability or charging state.
Example Apps
To see working examples of the concepts covered in this guide, check out the following sample projects:
-
Custom Broadcast – Demonstrates registering a receiver in the manifest to listen for a custom action.
-
Dynamic Broadcast – Shows how to dynamically register and unregister a connectivity change receiver.
-
LocalBroadcastManager – Illustrates communicating between components in an app using
LocalBroadcastManager
.
Conclusion
We‘ve covered a lot of ground in this guide to Android broadcast receivers. You should now have a solid understanding of what broadcast receivers are, how to register them, how to send your own broadcasts, and best practices to adhere to.
Broadcast receivers are a fundamental building block for creating Android apps that are well integrated with the surrounding system and other apps. By responding to system events and app-specific broadcasts, you can craft rich, dynamic experiences for your users.
That said, it‘s also important to understand the limitations and performance implications of broadcast receivers, especially in light of Android‘s evolving restrictions in recent versions. In many cases, newer APIs like JobScheduler
may be a better choice for scheduling background work.
I hope this guide has been a helpful introduction to the world of Android broadcast receivers. Remember to consult the official Android documentation for the most up-to-date and detailed information on changes between versions. Happy broadcasting!