[ Web Proxy ]
URL:
Viewing: https://developer.android.com/develop/background-work/background-tasks/broadcasts [Back]  [Original]

Broadcasts overview  |  Background work  |  Android Developers Skip to main content
Essentials Design & Plan Develop Google Play Blog
Search:
Android Studio
Android Developers [Android Developers]

Broadcasts overview Stay organized with collections Save and categorize content based on your preferences.

Android apps send and receive broadcast messages from the Android system and other Android apps, similar to the publish-subscribe design pattern. The system and apps typically send broadcasts when certain events occur. For example, the Android system sends broadcasts when various system events occur, such as system boot or device charging. Apps also send custom broadcasts, for example, to notify other apps of something that might interest them (for example, new data download).

Apps can register to receive specific broadcasts. When a broadcast is sent, the system automatically routes broadcasts to apps that have subscribed to receive that particular type of broadcast.

Generally speaking, broadcasts can be used as a messaging system across apps and outside of the normal user flow. However, you must be careful not to abuse the opportunity to respond to broadcasts and run jobs in the background that can contribute to a slow system performance.

Note: The system optimizes the delivery of broadcasts in order to maintain optimal system health. Therefore, delivery times of broadcasts are not guaranteed. Apps that need low-latency interprocess communication should consider bound services.

About system broadcasts

The system automatically sends broadcasts when various system events occur, such as when the system switches in and out of Airplane Mode. All subscribed apps receive these broadcasts.

The Intent object wraps the broadcast message. The action string identifies the event that occurred, such as android.intent.action.AIRPLANE_MODE. The intent might also include additional information bundled into its extra field. For example, the Airplane Mode intent includes a boolean extra that indicates whether or not Airplane Mode is on.

For more information about how to read intents and get the action string from an intent, see Intents and Intent Filters.

System broadcast actions

For a complete list of system broadcast actions, see the BROADCAST_ACTIONS.TXT file in the Android SDK. Each broadcast action has a constant field associated with it. For example, the value of the constant ACTION_AIRPLANE_MODE_CHANGED is android.intent.action.AIRPLANE_MODE. Documentation for each broadcast action is available in its associated constant field.

Changes to system broadcasts

As the Android platform evolves, it periodically changes how system broadcasts behave. Keep the following changes in mind to support all versions of Android.

Android 16

In Android 16, broadcast delivery order using the android:priority attribute or IntentFilter.setPriority() across different processes won't be guaranteed. Broadcast priorities are only respected within the same application process rather than across all processes.

Also, broadcast priorities are automatically confined to the range (SYSTEM_LOW_PRIORITY + 1, SYSTEM_HIGH_PRIORITY - 1). Only system components are allowed to set SYSTEM_LOW_PRIORITY, SYSTEM_HIGH_PRIORITY as broadcast priority.

Android 14

While apps are in a cached state, the system optimizes broadcast delivery for system health. For example, the system defers less important system broadcasts such as ACTION_SCREEN_ON while the app is in a cached state. Once the app goes from the cached state into an active process lifecycle, the system delivers any deferred broadcasts.

Important broadcasts that are declared in the manifest temporarily remove apps from the cached state for delivery.

Android 9

Beginning with Android 9 (API level 28), The NETWORK_STATE_CHANGED_ACTION broadcast doesn't receive information about the user's location or personally identifiable data.

If your app is installed on a device running Android 9.0 (API level 28) or higher, the system doesn't include SSIDs, BSSIDs, connection information, or scan results in Wi-Fi broadcasts. To get this information, call getConnectionInfo() instead.

Android 8.0

Beginning with Android 8.0 (API level 26), the system imposes additional restrictions on manifest-declared receivers.

If your app targets Android 8.0 or higher, you cannot use the manifest to declare a receiver for most implicit broadcasts (broadcasts that don't target your app specifically). You can still use a context-registered receiver when the user is actively using your app.

Android 7.0

Android 7.0 (API level 24) and higher don't send the following system broadcasts:

Also, apps targeting Android 7.0 and higher must register the CONNECTIVITY_ACTION broadcast using registerReceiver(BroadcastReceiver, IntentFilter). Declaring a receiver in the manifest doesn't work.

Receive broadcasts

Apps can receive broadcasts in two ways: through context-registered receivers and manifest-declared receivers.

Context-registered receivers

Context-registered receivers receive broadcasts as long as their registering context is valid. This is typically between the calls to registerReceiver and unregisterReceiver. The registering context also becomes invalid when the system destroys the corresponding context. For example, if you register within an Activity context, you receive broadcasts as long as the activity remains active. If you register with the Application context, you receive broadcasts as long as the app runs.

To register a receiver with a context, perform the following steps:

  1. In your app's module-level build file, include version 1.9.0 or higher of the AndroidX Core library:

    Groovy

    dependencies {
        def core_version = "1.19.0"
    
        // Java language implementation
        implementation "androidx.core:core:$core_version"
        // Kotlin
        implementation "androidx.core:core-ktx:$core_version"
    
        // To use RoleManagerCompat
        implementation "androidx.core:core-role:1.1.0"
    
        // To use the Animator APIs
        implementation "androidx.core:core-animation:1.0.0"
        // To test the Animator APIs
        androidTestImplementation "androidx.core:core-animation-testing:1.0.0"
    
        // Optional - To enable APIs that query the performance characteristics of GMS devices.
        implementation "androidx.core:core-performance:1.0.0"
    
        // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google
        implementation "androidx.core:core-google-shortcuts:1.1.0"
    
        // Optional - to support backwards compatibility of RemoteViews
        implementation "androidx.core:core-remoteviews:1.1.0"
    
        // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12
        implementation "androidx.core:core-splashscreen:1.2.0"
    }

    Kotlin

    dependencies {
        val core_version = "1.19.0"
    
        // Java language implementation
        implementation("androidx.core:core:$core_version")
        // Kotlin
        implementation("androidx.core:core-ktx:$core_version")
    
        // To use RoleManagerCompat
        implementation("androidx.core:core-role:1.1.0")
    
        // To use the Animator APIs
        implementation("androidx.core:core-animation:1.0.0")
        // To test the Animator APIs
        androidTestImplementation("androidx.core:core-animation-testing:1.0.0")
    
        // Optional - To enable APIs that query the performance characteristics of GMS devices.
        implementation("androidx.core:core-performance:1.0.0")
    
        // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google
        implementation("androidx.core:core-google-shortcuts:1.1.0")
    
        // Optional - to support backwards compatibility of RemoteViews
        implementation("androidx.core:core-remoteviews:1.1.0")
    
        // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12
        implementation("androidx.core:core-splashscreen:1.2.0")
    }
  2. Create an instance of BroadcastReceiver:

    Kotlin

    val myBroadcastReceiver = MyBroadcastReceiver()
    

    Java

    MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
    
  3. Create an instance of IntentFilter:

    Kotlin

    val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")
    

    Java

    IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");
    
  4. Choose whether the broadcast receiver should be exported and visible to other apps on the device. If this receiver is listening for broadcasts sent from the system or from other appseven other apps that you ownuse the RECEIVER_EXPORTED flag. If instead this receiver is listening only for broadcasts sent by your app, use the RECEIVER_NOT_EXPORTED flag.

    Some system broadcasts come from highly privileged apps, such as Bluetooth and telephony, that are part of the Android framework but don't run under the system's unique process ID (UID). To receive all system broadcasts, including broadcasts from highly privileged apps, flag your receiver with RECEIVER_EXPORTED.

    If you flag your receiver with RECEIVER_NOT_EXPORTED, the receiver is able to receive some system broadcasts and broadcasts from your app, but not broadcasts from the highly privileged apps.

    If your app is listening for multiple broadcasts, but only some should be flagged RECEIVER_NOT_EXPORTED and some RECEIVER_EXPORTED, partition the broadcasts among different broadcast receivers.

    Kotlin

    val listenToBroadcastsFromOtherApps = false
    val receiverFlags = if (listenToBroadcastsFromOtherApps) {
        ContextCompat.RECEIVER_EXPORTED
    } else {
        ContextCompat.RECEIVER_NOT_EXPORTED
    }
    

    Java

    boolean listenToBroadcastsFromOtherApps = false;
    int receiverFlags = listenToBroadcastsFromOtherApps
            ? ContextCompat.RECEIVER_EXPORTED
            : ContextCompat.RECEIVER_NOT_EXPORTED;
    
    Caution: If you export the broadcast receiver, other apps could send unprotected broadcasts to your app.
  5. Register the receiver by calling registerReceiver():

    Kotlin

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)
    

    Java

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);
    
  6. To stop receiving broadcasts, call unregisterReceiver(android.content.BroadcastReceiver). Be sure to unregister the receiver when you no longer need it or the context is no longer valid.

Unregister your broadcast receiver

While the broadcast receiver is registered, it holds a reference to the Context that you registered it with. This can potentially cause leaks if the receiver's registered scope exceeds the Context lifecycle scope. For example, this can occur when you register a receiver on an Activity scope, but you forget to unregister it when the system destroys the Activity. Therefore, always unregister your broadcast receiver.

Kotlin

class MyActivity : ComponentActivity() {
    private val myBroadcastReceiver = MyBroadcastReceiver()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags)
        setContent { MyApp() }
    }

    override fun onDestroy() {
        super.onDestroy()
        // When you forget to unregister your receiver here, you're causing a leak!
        this.unregisterReceiver(myBroadcastReceiver)
    }
}

Java

class MyActivity extends ComponentActivity {
    MyBroadcastReceiver myBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ...
        ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags);
        // Set content
    }
}

Register receivers in the smallest scope

Your broadcast receiver should only be registered when you're actually interested in the result. Choose the smallest possible receiver scope:

Create stateful and stateless composable

Compose has stateful and stateless composables. Registering or unregistering a broadcast receiver inside a composable makes it stateful. The composable is not a deterministic function that renders the same content when passed the same parameters. Internal state can change based on calls to the registered broadcast receiver.

As a best practice in Compose, we recommend that you split your composables into stateful and stateless versions. Therefore, we recommend that you hoist the creation of the broadcast receiver out of a Composable to make it stateless:

@Composable
fun MyStatefulScreen() {
    val myBroadcastReceiver = remember { MyBroadcastReceiver() }
    val context = LocalContext.current
    LifecycleStartEffect(true) {
        // ...
        ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, flags)
        onStopOrDispose { context.unregisterReceiver(myBroadcastReceiver) }
    }
    MyStatelessScreen()
}

@Composable
fun MyStatelessScreen() {
    // Implement your screen
}

Manifest-declared receivers

If you declare a broadcast receiver in your manifest, the system launches your app when the broadcast is sent. If the app is not already running, the system launches the app.

Note: If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for implicit broadcasts, except for a few implicit broadcasts that are exempted from that restriction. Implicit broadcasts are broadcasts that don't target your app specifically. In most cases, you can use scheduled jobs instead.

To declare a broadcast receiver in the manifest, perform the following steps:

  1. Specify the <receiver> element in your app's manifest.

    <!-- If this receiver listens for broadcasts sent from the system or from
         other apps, even other apps that you own, set android:exported to "true". -->
    <receiver android:name=".MyBroadcastReceiver" android:exported="false">
        <intent-filter>
            <action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
        </intent-filter>
    </receiver>
    

    The intent filters specify the broadcast actions your receiver subscribes to.

  2. Subclass BroadcastReceiver and implement onReceive(Context, Intent). The broadcast receiver in the following example logs and displays the contents of the broadcast:

    Kotlin

    class MyBroadcastReceiver : BroadcastReceiver() {
    
        @Inject
        lateinit var dataRepository: DataRepository
    
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == "com.example.snippets.ACTION_UPDATE_DATA") {
                val data = intent.getStringExtra("com.example.snippets.DATA") ?: "No data"
                // Do something with the data, for example send it to a data repository:
                dataRepository.updateData(data)
            }
        }
    }
    

    Java

    public static class MyBroadcastReceiver extends BroadcastReceiver {
    
        @Inject
        DataRepository dataRepository;
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Objects.equals(intent.getAction(), "com.example.snippets.ACTION_UPDATE_DATA")) {
                String data = intent.getStringExtra("com.example.snippets.DATA");
                // Do something with the data, for example send it to a data repository:
                if (data != null) { dataRepository.updateData(data); }
            }
        }
    }
    

The system package manager registers the receiver when the app is installed. The receiver then becomes a separate entry point into your app which means that the system can start the app and deliver the broadcast if the app is not running.

The system creates a new BroadcastReceiver component object to handle each broadcast that it receives. This object is valid only for the duration of the call to onReceive(Context, Intent). Once your code returns from this method, the system considers the component no longer active.

Effects on process state

Whether your BroadcastReceiver is operating or not affects its contained process, which can alter its system-killing likelihood. A foreground process executes a receiver's onReceive() method. The system runs the process except under extreme memory pressure.

The system deactivates the BroadcastReceiver after onReceive(). The receiver's host process's significance depends on its app components. If that process hosts only a manifest-declared receiver, the system might kill it after onReceive() to free resources for other more critical processes. This is common for apps the user has never or not recently interacted with.

Thus, broadcast receivers shouldn't initiate long-running background threads. The system can stop the process at any moment after onReceive() to reclaim memory, terminating the created thread. To keep the process alive, schedule a JobService from the receiver using the JobScheduler so the system knows the process is still working. Background Work Overview provides more details.

Send broadcasts

Android provides two ways for apps to send broadcasts:

The following code snippet demonstrates how to send a broadcast by creating an Intent and calling sendBroadcast(Intent).

Kotlin

val intent = Intent("com.example.snippets.ACTION_UPDATE_DATA").apply {
    putExtra("com.example.snippets.DATA", newData)
    setPackage("com.example.snippets")
}
context.sendBroadcast(intent)

Java

Intent intent = new Intent("com.example.snippets.ACTION_UPDATE_DATA");
intent.putExtra("com.example.snippets.DATA", newData);
intent.setPackage("com.example.snippets");
context.sendBroadcast(intent);

The broadcast message is wrapped in an Intent object. The intent's action string must provide the app's Java package name syntax and uniquely identify the broadcast event. You can attach additional information to the intent with putExtra(String, Bundle). You can also limit a broadcast to a set of apps in the same organization by calling setPackage(String) on the intent.

Note: Although you can use intents for both sending broadcasts and starting activities with startActivity(Intent), these actions are completely unrelated. Broadcast receivers can't see or capture intents used to start an activity; likewise, when you broadcast an intent, you can't find or start an activity.

Restrict broadcasts with permissions

Permissions allow you to restrict broadcasts to the set of apps that hold certain permissions. You can enforce restrictions on either the sender or receiver of a broadcast.

Send broadcasts with permissions

When you call sendBroadcast(Intent, String) or sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) , you can specify a permission parameter. Only receivers who have requested that permission with the <uses-permission> tag in their manifest can receive the broadcast. If the permission is dangerous, you must grant the permission before the receiver can receive the broadcast. For example, the following code sends a broadcast with a permission:

Kotlin

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)

Java

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);

To receive the broadcast, the receiving app must request the permission as follows:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

You can specify either an existing system permission like BLUETOOTH_CONNECT or define a custom permission with the <permission> element. For information on permissions and security in general, see the System Permissions.

Note: Custom permissions are registered when the app is installed. The app that defines the custom permission must be installed before the app that uses it.

Receive broadcasts with permissions

If you specify a permission parameter when registering a broadcast receiver (either with registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) or in <receiver> tag in your manifest), then only broadcasters who have requested the permission with the <uses-permission> tag in their manifest can send an Intent to the receiver. If the permission is dangerous, the broadcaster must also be granted the permission.

For example, assume your receiving app has a manifest-declared receiver as follows:

<!-- If this receiver listens for broadcasts sent from the system or from
     other apps, even other apps that you own, set android:exported to "true". -->
<receiver
    android:name=".MyBroadcastReceiverWithPermission"
    android:permission="android.permission.ACCESS_COARSE_LOCATION"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
    </intent-filter>
</receiver>

Or your receiving app has a context-registered receiver as follows:

Kotlin

ContextCompat.registerReceiver(
    context, myBroadcastReceiver, filter,
    android.Manifest.permission.ACCESS_COARSE_LOCATION,
    null, // scheduler that defines thread, null means run on main thread
    receiverFlags
)

Java

ContextCompat.registerReceiver(
        context, myBroadcastReceiver, filter,
        android.Manifest.permission.ACCESS_COARSE_LOCATION,
        null, // scheduler that defines thread, null means run on main thread
        receiverFlags
);

Then, to be able to send broadcasts to those receivers, the sending app must request the permission as follows:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Security considerations

Here are some security considerations for sending and receiving broadcasts:

Content and code samples on this page are subject to the licenses described in the Content License. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.

Last updated 2026-08-18 UTC.

[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2026-08-18 UTC."],[],[]]

Web Proxy Viewer  |  New URL  |  Original Page