Understanding Android BroadcastReceiver: Concepts, Usage, and Best Practices

BroadcastReceiver Overview

BroadcastReceiver is one of Android's four core components. Unlike Activity, it has no visible UI. It involves two roles: the broadcast sender and the broadcast receiver (Receiver). The broadcast itself is an Intent. An app can send and receive its own broadcasts, receive broadcasts from the system or other apps, or send broadcasts to other applications.

A sender invokes methods like Context.sendBroadcast to dispatch a broadcast. A receiver registers via Context.registerReceiver() (dynamic registration) or via the <receiver> tag in AndroidManifest.xml (static registration). When a broadcast is sent, the system matches the Intent against all registered receivers' IntentFilters. If a match is found, the corresponding receiver's onReceive method is executed.

Differences Between Dynamic and Static Registration

  • Async operations after onReceive: For statically registered receivers, the broadcast object no longer exists after onReceive finishes. Therefore, you cannot perform asynchronous operations like bindService; you can only use startService. To interact with a service, use peekService.
  • Lifecycle control: Dynamic registration allows manual registration and unregistration; static registration is performed by the system at boot time and cannot be manually controlled—it remains active as long as the app is installed.
  • Resource usage: Dynamic registration can be managed to reduce resource consumption; static registration is always active.
  • Validity period: A dynamically registered receiver becomes invalid when the registering Context is destroyed or when unregisterReceiver is called. A statically registered receiver remains valid until the app is deleted.
  • Recursive registration: In onReceive of a dynamically registered receiver, you can call registerReceiver again. This is not allowed for statically registered receivers.
  • Typical use cases: Dynamic registration is suitable for app-specific send/receive patterns; static registration is common for system broadcasts that should be received regardless of app state.

Example Code

public class BroadcastReceiverDemo extends Activity {

    private static final String ACTION_SEND = "com.trinea.android.demo.BroadcastReceiverDemo.sendBroadcast";
    private static final String MSG_KEY     = "msg";

    private MyBroadcastReceiver receiver;
    private Button sendBtn;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.broadcast_receiver_demo);

        receiver = new MyBroadcastReceiver();

        sendBtn = (Button) findViewById(R.id.sendBroadcast);
        sendBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendBtn.setText("Sending...");
                sendBtn.setClickable(false);
                Intent i = new Intent(ACTION_SEND);
                i.putExtra(MSG_KEY, "The Voice is starting now!");
                sendBroadcast(i);
            }
        });
    }

    @Override
    public void onPause() {
        super.onPause();
        unregisterReceiver(receiver);
    }

    @Override
    public void onResume() {
        super.onResume();
        registerReceiver(receiver, new IntentFilter(ACTION_SEND));
    }

    public class MyBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            sendBtn.setText("Send Broadcast");
            sendBtn.setClickable(true);
            Toast.makeText(context, intent.getStringExtra(MSG_KEY), Toast.LENGTH_SHORT).show();
        }
    }
}

The layout file broadcast_receiver_demo.xml contains a simple Button with id sendBroadcast.

Key steps:

  • Create a BroadcastReceiver by extending BroadcastReceiver and overriding onReceive.
  • Register with registerReceiver, unregister with unregisterReceiver, and send with sendBroadcast.
  • Placing registration in onResume and unregistration in onPause improves resource efficiency. For a persistent receiver, register in onCreate and unregister in onDestroy.
  • Static registration in AndroidManifest.xml:
<receiver android:name="MyBroadcastReceiver">
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>

Lifecycle

The lifecycle of a BroadcastReceiver ends when onReceive returns. Therefore, avoid performing asynchronous work (e.g., binding a Service, starting a thread for downloads) directly in onReceive, as the process may be killed before the async task completes. Also, onReceive runs on the main thread and must complete within 10 seconds to avoid ANR. Offload long-running operations (network, database, dialogs) to a Service; use Notification instead of dialogs.

Security Considerations

  • When an app sends a broadcast, the system matches it against all registered receivers. To restrict receivers, use sendBroadcast(Intent, String) to require a permission, or Intent.setPackage to limit the broadcast to a specific app.
  • When an app registers a receiver, it can receive broadcasts from any sender matching its IntentFilter. For dynamic registration, use registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) to require a permission from the sender. For static registration, set android:exported="false" to prevent external apps from sending broadcasts to it.
  • These issues can be mitigated using LocalBroadcastManager, which restricts broadcasts to the current app (see below).
  • Use android:protectionLevel appropriately.

Broadcast Types

Normal Broadcast

Sent via Context.sendBroadcast. Receivers receive it in an unpredictable order; they cannot modify the broadcast or prevent others from receiving it.

Ordered Broadcast

Sent via Context.sendOrderedBroadcast. Receivers receive the broadcast in a defined order based on priority (android:priority, range -1000 to 1000). Each receiver can modify the broadcast's result data or abort it using abortBroadcast(). Even if a higher-priority receiver aborts the broadcast, the result receiver specified in sendOrderedBroadcast parameters will still receive the final result. getResultExtras returns a Bundle that can be used to read/write data.

Special BroadcastReceivers

LocalBroadcastManager

Introduced to solve security and efficiency problems. It confines broadcasts to the app's own process, improving security and performance.

  • Requires Android Support Library.
  • Usage: LocalBroadcastManager.getInstance(context).sendBroadcast(intent) for sending, LocalBroadcastManager.getInstance(context).registerReceiver(...) for registration, LocalBroadcastManager.getInstance(context).unregisterReceiver(...) for unregistration.

Sticky Broadcast

If a receiver registers after the broadcast was sent, it normally won't recieve it. Sticky broadcasts persist the last broadcast Intent so that newly registered receivers can receive it. If multiple sticky broadcasts of the same action are sent before registration, only the most recent one is delivered. System network state changes are sticky broadcasts.

  • Requires permission <uses-permission android:name="android.permission.BROADCAST_STICKY" />.
  • Send via sendStickyBroadcast(Intent), remove via removeStickyBroadcast(Intent).

Ordered Broadcast

Described above in Broadcast Types.

Sticky Ordered Broadcast

Combines sticky and ordered behavior. Sent via sendStickyOrderedBroadcast.

References

Tags: Android BroadcastReceiver LocalBroadcastManager Sticky Broadcast Ordered Broadcast

Posted on Thu, 17 Sep 2026 16:30:13 +0000 by woobarb