Devesh Rx Logo
Devesh Rx Blog

Android Broadcast Receivers: The Complete Guide to Listening and Sending Events (Part 5)

April 1, 2026

Android Broadcast Receivers: The Complete Guide to Listening and Sending Events (Part 5)

Have you ever wondered how your favorite Android app instantly knows when your phone enters airplane mode or when the battery drops below 15%? The secret lies in a core Android component: the Broadcast Receiver.

Whether you are looking to understand the fundamentals of Broadcast Receivers (BR) or want to learn how to implement and trigger them in your application, this guide has you covered. Let’s dive into how these invisible messengers keep your apps connected to the Android system and each other.


What is a Broadcast Receiver?

Within the Android operating system, certain background events are constantly happening. Examples include the user turning Airplane Mode on or off, switching Wi-Fi or Bluetooth states, or simply connecting their phone to a charger.

Whenever these actions occur, the Android OS broadcasts these changes across the entire system as broadcast events. Applications can capture these events to stay updated. By setting up a Broadcast Receiver inside your app, you can keep a close eye on specific events happening in the Android OS or on the device itself.

Types of Broadcast Events

There are two main types of broadcast events your receiver can listen for:

  • System Events: These are events inherently associated with the Android system itself, such as turning on Airplane Mode, toggling Wi-Fi, or connecting to a charger.
  • Custom Events: These are non-system events created by third-party applications or your own app. Your application can create custom events to be broadcasted and sent to other apps across the Android operating system.

Two Methods for Implementing Broadcast Receivers

To implement a broadcast receiver in your application, you can use two primary approaches:

  1. The Static Method: You declare your broadcast receiver directly in the AndroidManifest.xml file. Because it is static, you cannot change this receiver dynamically at runtime.
  2. The Dynamic Method: You programmatically create and register the receiver during the app’s runtime. This gives you the flexibility to turn the broadcast receiver on or off while the application is running.

Let’s dive into three practical examples to see how both methods work.


Example 1: Creating a Custom Static Broadcast Receiver

In this first example, we will create a static receiver designed to listen for our own custom events.

Step 1: Create the Kotlin Class

First, create a new Kotlin class file (e.g., StaticReceiver.kt) and add the BroadcastReceiver constructor to turn the class into a receiver. Next, override the onReceive event. This function triggers whenever your app receives a broadcast.

Broadcasts are received via an Intent. Think of an intent as a messenger that transfers data from one application to another. Inside the onReceive function, we use this intent to extract extra data (using a key like extra_msg). Once the broadcast is received, you can display this extracted data as a simple Toast message or print it in the Android Logcat.

// StaticReceiver.kt
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.widget.Toast

class StaticReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // Extract the message from the intent
        val message = intent.getStringExtra("extra_msg") ?: "No message"
        
        // Display the message as a Toast
        Toast.makeText(context, message, Toast.LENGTH_LONG).show()
    }
}

Step 2: Register in the Android Manifest

Next, you must mention this receiver in your AndroidManifest.xml file:

  • Open your manifest and add a <receiver> tag.
  • Add the name of your Kotlin file (e.g., .StaticReceiver).
  • Set the android:exported property. Set it to true if you want to allow third-party applications to trigger your receiver. If you only want to receive broadcasts from your own app, set it to false.
  • Inside the receiver tag, create an <intent-filter> and add an action name (e.g., com.devish.broadcastreceiverapp.static_action). This unique string links directly to your custom broadcast event.
<!-- AndroidManifest.xml -->
<receiver 
    android:name=".StaticReceiver"
    android:exported="false">
    <intent-filter>
        <action android:name="com.devish.broadcastreceiverapp.static_action" />
    </intent-filter>
</receiver>

Step 3: Trigger the Broadcast

To trigger this static receiver, go to your MainActivity.kt file. You can attach this logic to a button click:

  1. Create a new Intent and pass in the exact custom action string you defined in the manifest.
  2. Use putExtra to add your message data (e.g., “Hello static event trigger”).
  3. Mention your package name using setPackage().
  4. Finally, use the context to call sendBroadcast(intent).
// MainActivity.kt
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Button(onClick = { triggerStaticBroadcast() }) {
                Text("Send Static Broadcast")
            }
        }
    }

    private fun triggerStaticBroadcast() {
        val intent = Intent("com.devish.broadcastreceiverapp.static_action")
        intent.putExtra("extra_msg", "Hello static event trigger")
        // Restrict the broadcast to your own app package
        intent.setPackage(packageName) 
        sendBroadcast(intent)
    }
}

When the button is clicked, the system routes the event to your StaticReceiver class, which captures it and displays your Toast message!


Example 2: Listening for System Events (Airplane Mode)

Now, let’s look at how to listen for a System Event, specifically toggling Airplane Mode.

Step 1: Set Up the Receiver

Create a new file named AeroplaneModeReceiver.kt. Just like the first example, use the intent inside the onReceive block to check the state. In this case, the state is a boolean—if it returns true, Airplane Mode is on; if false, it is off. We will display this state as a Toast message.

// AeroplaneModeReceiver.kt
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.widget.Toast

class AeroplaneModeReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // The Android OS passes the state as a boolean using the key "state"
        val isAirplaneModeOn = intent.getBooleanExtra("state", false)
        
        if (isAirplaneModeOn) {
            Toast.makeText(context, "Airplane Mode is ON", Toast.LENGTH_LONG).show()
        } else {
            Toast.makeText(context, "Airplane Mode is OFF", Toast.LENGTH_LONG).show()
        }
    }
}

Step 2: Declare the System Action

In your AndroidManifest.xml, create a <receiver> tag for this file and set exported="true". The most critical step here is adding the specific action string reserved by the Android OS for this event: android.intent.action.AIRPLANE_MODE.

(Note: If you want to listen for charging or Bluetooth events, you would use their respective reserved system strings, which can be found in the official Android documentation).

<!-- AndroidManifest.xml -->
<receiver 
    android:name=".AeroplaneModeReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.AIRPLANE_MODE" />
    </intent-filter>
</receiver>

Step 3: Register Dynamically at Runtime

Since we are listening to system events, we need to register this receiver dynamically at runtime. Using Jetpack Compose in the MainActivity.kt file:

  • Inside a DisposableEffect function (which runs once at the start), create an IntentFilter that targets the AIRPLANE_MODE action string.
  • Call registerReceiver(), passing in your AeroplaneModeReceiver and the intent filter.
  • Crucial Step: When the user leaves the screen or application, you must clean up. Go to the onDispose function and call unregisterReceiver() to safely detach it.
// MainActivity.kt
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.platform.LocalContext

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AirplaneModeScreen()
        }
    }
}

@Composable
fun AirplaneModeScreen() {
    val context = LocalContext.current
    val airplaneReceiver = AeroplaneModeReceiver()

    DisposableEffect(Unit) {
        // Create the intent filter for the system event
        val filter = IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)
        
        // Register the receiver dynamically
        context.registerReceiver(airplaneReceiver, filter)

        // Clean up when the Composable is removed from the screen
        onDispose {
            context.unregisterReceiver(airplaneReceiver)
        }
    }
    
    // Your UI goes here...
}

When you run this on a virtual device and toggle Airplane Mode, your app will immediately display “Airplane Mode is ON” or “Airplane Mode is OFF.”


Example 3: Creating a Dynamic Custom Broadcast Receiver

Unlike the static method, you do not need to touch the AndroidManifest.xml file for a purely dynamic custom receiver. Everything is handled during runtime.

Step 1 & 2: Create the Receiver Object and Register it

  1. Define a custom name variable for your broadcast action (e.g., custom_action).
  2. Create an object of BroadcastReceiver directly in your code.
  3. Inside this object, override the onReceive function to extract the extra_data string from the intent and save it to a variable.
  4. Navigate to the onStart event of your activity. Here, create an IntentFilter using your custom_action string. The purpose of this filter is to ignore other system broadcasts and ensure you only receive your specific custom event. Next, register it by calling registerReceiver().

Step 3 & 4: Send the Custom Broadcast and Unregister

Create a function to send the event. Generate an Intent with your custom_action string, attach your putExtra data (e.g., “Hello from dynamic receiver”), and execute sendBroadcast(intent).

To prevent memory leaks, always remember to call unregisterReceiver() when the user closes down the app or leaves the screen.

// MainActivity.kt
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity

class MainActivity : ComponentActivity() {

    // Define the custom action string
    private val customAction = "com.devish.broadcastreceiverapp.custom_action"
    
    // Variable to hold the received data
    private var receivedMessage = ""

    // Create the receiver object programmatically
    private val dynamicReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            // Extract data and save it
            receivedMessage = intent.getStringExtra("extra_data") ?: "No data"
            Toast.makeText(context, receivedMessage, Toast.LENGTH_SHORT).show()
        }
    }

    override fun onStart() {
        super.onStart()
        // Step 2: Create the filter and register the receiver
        val filter = IntentFilter(customAction)
        registerReceiver(dynamicReceiver, filter)
    }

    override fun onStop() {
        super.onStop()
        // Step 4: Unregister to prevent memory leaks
        unregisterReceiver(dynamicReceiver)
    }

    // Step 3: Function to send the custom broadcast
    private fun sendDynamicBroadcast() {
        val intent = Intent(customAction)
        intent.putExtra("extra_data", "Hello from dynamic receiver")
        sendBroadcast(intent)
    }
}

Conclusion

Implementing Broadcast Receivers is straightforward once you understand how intents and intent filters work together. You can choose either the static method (via the Android Manifest) or the dynamic method (via programmatic runtime registration), depending on what works best for your specific application needs.

Thank you for reading! If you want to master more essential skills, be sure to check out our full playlist on the Fundamentals of Android App Development to learn everything you need to build high-quality Android applications.


📌 Full Course Playlist https://www.youtube.com/playlist?list=PLO1OrQEU0vHNmD9Xqzs-qXwzzwrDvdhVu

#Tutorial
0 Introduction
1 Setting up Android Studio IDE
2 Mastering Android Studio: Navigating the IDE & Project Structure
3 Android Activity & Lifecycle Explained
4 Android Services: Background, Foreground, and Bound Services Explained
5 Android Broadcast Receivers: The Complete Guide to Listening and Sending Events

~ ~ THANK YOU FOR READING ~ ~

Share: