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 afteronReceivefinishes. Therefore, you cannot perform asynchronous operations likebindService; you can only usestartService. To interact with a service, usepeekService. - 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
unregisterReceiveris called. A statically registered receiver remains valid until the app is deleted. - Recursive registration: In
onReceiveof a dynamically registered receiver, you can callregisterReceiveragain. 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
BroadcastReceiverand overridingonReceive. - Register with
registerReceiver, unregister withunregisterReceiver, and send withsendBroadcast. - Placing registration in
onResumeand unregistration inonPauseimproves resource efficiency. For a persistent receiver, register inonCreateand unregister inonDestroy. - 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, orIntent.setPackageto 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, setandroid: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:protectionLevelappropriately.
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 viaremoveStickyBroadcast(Intent).
Ordered Broadcast
Described above in Broadcast Types.
Sticky Ordered Broadcast
Combines sticky and ordered behavior. Sent via sendStickyOrderedBroadcast.