Broadcast Receiver in Android with Example – Complete Guide
Broadcast Receivers are one of the most important Android components when you want your app to react to system events or messages from other apps. With a BroadcastReceiver, your app can listen for events like device boot, connectivity changes, battery status, or even custom events that you broadcast yourself. In this complete guide, you will learn what a Broadcast Receiver is, how it works, how to register it, and how to implement it with a clean, real-world example.
What Is a Broadcast Receiver in Android?
A BroadcastReceiver is a component that allows your app to respond to broadcast messages sent by the Android system or other applications. These messages are delivered using Intent objects and are often used to signal that something important has happened, such as the device booting, power being connected, or a custom event inside your app.
You can think of a BroadcastReceiver as a small, focused listener that wakes up only when a specific event occurs. It does not have a user interface. Instead, it receives the broadcast in its onReceive() method, performs a quick operation, and then finishes.
How Broadcast Receivers Work Internally
Android uses an intent-based publish–subscribe model for broadcasts. When a broadcast is sent, the system looks for all registered receivers whose intent filters match the broadcast’s action, category, and data. Matching receivers then get a chance to handle the event.
The basic workflow is:
- An app or the system sends a broadcast using methods like
sendBroadcast()orsendOrderedBroadcast(). - Android resolves the broadcast against all intent filters of registered BroadcastReceivers.
- The system creates instances of the matching receivers (if needed) and calls their
onReceive()method. - Once
onReceive()finishes, the receiver can be destroyed and its process may be killed if no longer needed.
This “fire-and-forget” pattern means you should do only short, fast work inside onReceive(). For longer tasks, start a Service or use WorkManager from inside the receiver.
Types of Broadcasts: System and Custom
Broadly, there are two main sources of broadcasts in Android:
- System broadcasts: Sent by Android itself for events like
ACTION_BOOT_COMPLETED,ACTION_BATTERY_CHANGED,ACTION_AIRPLANE_MODE_CHANGED, etc. - Custom (app-defined) broadcasts: Sent by your app using explicit or implicit intents to signal internal events, such as “user logged out” or “data refreshed”.
System broadcasts let your app react to global state changes, while custom broadcasts help different parts of your app communicate with each other in a decoupled way.
Manifest-Declared vs Context-Registered Receivers
There are two main ways to register a BroadcastReceiver in Android, and each has different behavior and use cases.
1. Manifest-Declared (Static) Broadcast Receivers
With manifest registration, you declare the receiver in the AndroidManifest.xml. These receivers can be triggered even when your app is not running, and Android may start your app process to handle the broadcast.
Basic structure in the manifest:
<receiver
android:name=".MyBootReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Manifest-declared receivers are useful when you need to react to important system events that can occur even when the app is closed, such as device boot or package installation. However, starting from Android 8.0 (API 26), many implicit system broadcasts can no longer be registered in the manifest to improve performance and battery life.
2. Context-Registered (Dynamic) Broadcast Receivers
Context-registered receivers are registered in code at runtime using registerReceiver() and unregistered with unregisterReceiver(). They exist only while the context that registered them (like an Activity or Service) is alive.
These receivers are perfect for cases where you only care about broadcasts while a particular screen is visible. For example, an Activity might listen for connectivity changes only while it is in the foreground.
override fun onResume() {
super.onResume()
val filter = IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)
registerReceiver(airplaneModeReceiver, filter)
}
override fun onPause() {
super.onPause()
unregisterReceiver(airplaneModeReceiver)
}
Remember to always unregister dynamic receivers to avoid memory leaks and unexpected behavior.
Implicit vs Explicit Broadcasts
Broadcast intents can be implicit or explicit, similar to normal intents:
- Implicit broadcasts do not specify a particular component; they rely on the action and intent filter to find matching receivers. Many system broadcasts are implicit, like
ACTION_POWER_CONNECTED. - Explicit broadcasts directly target a specific BroadcastReceiver class inside your own app using the component name.
For security and performance reasons, best practice is to use explicit broadcasts for your own app’s internal communication. Use implicit broadcasts when you truly want multiple apps to have a chance to respond to a shared system event.
Broadcast Receiver in Android – Example
Let’s implement a simple but practical example: a BroadcastReceiver that listens for changes in Airplane Mode and shows a Toast message when the user turns it on or off. This example uses a context-registered (dynamic) receiver so that it only listens while the Activity is in the foreground.
Step 1: Create the BroadcastReceiver Class
Create a new Kotlin class AirplaneModeChangeReceiver.kt that extends BroadcastReceiver and overrides onReceive():
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.provider.Settings
import android.widget.Toast
class AirplaneModeChangeReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Check if this is the airplane mode changed action
if (Intent.ACTION_AIRPLANE_MODE_CHANGED == intent.action) {
val isOn = Settings.Global.getInt(
context.contentResolver,
Settings.Global.AIRPLANE_MODE_ON, 0
) == 1
val message = if (isOn) {
"Airplane mode is ON"
} else {
"Airplane mode is OFF"
}
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}
}
This receiver reads the airplane mode setting and displays a short message whenever it changes.
Step 2: Register the Receiver Dynamically in an Activity
Next, use this receiver in your MainActivity. Register it in onResume() and unregister it in onPause() so it is active only while the Activity is visible.
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private val airplaneModeReceiver = AirplaneModeChangeReceiver()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onResume() {
super.onResume()
val filter = IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)
registerReceiver(airplaneModeReceiver, filter)
}
override fun onPause() {
super.onPause()
unregisterReceiver(airplaneModeReceiver)
}
}
Now, whenever you toggle airplane mode while this Activity is open, the Toast will appear. This simple example shows the complete flow: creating a receiver, registering it, reacting to the broadcast, and cleaning it up.
When to Use Broadcast Receivers
Broadcast Receivers are a good fit when you need to:
- Respond to important system events like boot completed, connectivity changes, battery status, locale changes, or time zone updates.
- Send and receive custom events across different parts of your own app without tightly coupling components.
- Trigger background work at certain times or under certain conditions using a receiver plus WorkManager or a service.
They are not ideal for continuous background work or long-running operations. Use them mainly as lightweight triggers that hand off real work to other components.
Best Practices and Common Pitfalls
To use Broadcast Receivers safely and effectively, keep these best practices in mind:
- Do minimal work in
onReceive(): Start a service, schedule a worker, or post a notification instead of doing heavy computation directly. - Avoid memory leaks: Unregister context-registered receivers in the correct lifecycle method (for example,
onPause()oronStop()), and do not hold long-lived references to Activities in receivers. - Respect Android version restrictions: Newer Android versions limit manifest-registered implicit broadcasts to reduce background work. Check documentation and use runtime registration or WorkManager when required.
- Use explicit broadcasts for internal events: This improves security and avoids other apps accidentally intercepting your intents.
- Handle export and permissions wisely: If your receiver is exported, define permissions or keep it non-exported if it is only for internal use.
Conclusion
Broadcast Receivers in Android provide a powerful mechanism for reacting to system-wide and application-specific events. By understanding how broadcasts work, the difference between manifest-declared and context-registered receivers, and when to use implicit or explicit intents, you can design event-driven features that are both efficient and secure.
With the example of the Airplane Mode change receiver, you have seen an end-to-end implementation: creating a receiver class, registering it, handling the broadcast, and avoiding common pitfalls. Apply these concepts to handle other broadcasts—such as connectivity changes, battery levels, or custom app events—and your Android apps will become more responsive, intelligent, and user-aware.

0 Comments