BroadcastReceivers & System Events

📖 Concept

BroadcastReceivers listen for system-wide or app-internal broadcast events. At the senior level, understand the security model, implicit broadcast restrictions, and modern alternatives.

How BroadcastReceivers work internally:

  1. An app or the system sends a broadcast Intent via sendBroadcast()
  2. The Intent goes to ActivityManagerService (AMS) via Binder
  3. AMS queries PackageManagerService for all registered receivers matching the IntentFilter
  4. AMS delivers the broadcast to each receiver's onReceive() method
  5. For manifest-registered receivers, AMS starts the app process if needed

Registration types:

  • Manifest-registered (static): Survives app death, limited to specific broadcasts since Android 8.0
  • Context-registered (dynamic): Active only while the registering component lives, no restrictions

Android 8.0+ implicit broadcast restrictions: Most implicit broadcasts can no longer wake up manifest-registered receivers. Exceptions: BOOT_COMPLETED, LOCALE_CHANGED, ACTION_TIMEZONE_CHANGED and a few others.

Ordered vs Normal broadcasts:

  • Normal: Delivered to all receivers simultaneously (no ordering guarantee)
  • Ordered: Delivered one at a time by priority. Receivers can abort propagation.

Modern alternatives:

  • For in-app events: Kotlin Flow, LiveData, or EventBus patterns
  • For scheduled work: WorkManager
  • For push notifications: FCM (Firebase Cloud Messaging)

💻 Code Example

codeTap to expand ⛶
1// Dynamic registration — preferred for most use cases
2class NetworkAwareActivity : AppCompatActivity() {
3 private val connectivityReceiver = object : BroadcastReceiver() {
4 override fun onReceive(context: Context, intent: Intent) {
5 val isConnected = intent.getBooleanExtra(
6 ConnectivityManager.EXTRA_NO_CONNECTIVITY, false
7 ).not()
8 handleConnectivityChange(isConnected)
9 }
10 }
11
12 override fun onStart() {
13 super.onStart()
14 val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
15 registerReceiver(connectivityReceiver, filter)
16 }
17
18 override fun onStop() {
19 super.onStop()
20 unregisterReceiver(connectivityReceiver) // Prevent leak
21 }
22}
23
24// Modern approach: Use ConnectivityManager.NetworkCallback instead
25class NetworkMonitor @Inject constructor(
26 private val connectivityManager: ConnectivityManager
27) {
28 val isConnected: StateFlow<Boolean> = callbackFlow {
29 val callback = object : ConnectivityManager.NetworkCallback() {
30 override fun onAvailable(network: Network) { trySend(true) }
31 override fun onLost(network: Network) { trySend(false) }
32 }
33 val request = NetworkRequest.Builder()
34 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
35 .build()
36 connectivityManager.registerNetworkCallback(request, callback)
37 awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
38 }.stateIn(CoroutineScope(Dispatchers.Default), SharingStarted.Lazily, false)
39}
40
41// LocalBroadcastManager alternative — use Kotlin Flow
42class EventBus {
43 private val _events = MutableSharedFlow<AppEvent>(extraBufferCapacity = 64)
44 val events: SharedFlow<AppEvent> = _events.asSharedFlow()
45
46 suspend fun emit(event: AppEvent) { _events.emit(event) }
47}

🏋️ Practice Exercise

Practice:

  1. List 5 implicit broadcasts that still work with manifest-registered receivers on Android 13+
  2. Implement a BroadcastReceiver that listens for airplane mode changes
  3. Why is LocalBroadcastManager deprecated? What should you use instead?
  4. Explain ordered broadcasts — when would you use them?
  5. Implement a network connectivity monitor using NetworkCallback and Flow

⚠️ Common Mistakes

  • Not unregistering dynamic receivers — memory leak and potential crash

  • Doing long-running work in onReceive() — it runs on the main thread and has a 10-second limit before ANR

  • Using manifest-registered receivers for implicit broadcasts on Android 8.0+ — they won't fire

  • Using LocalBroadcastManager (deprecated) — use Kotlin Flow or LiveData for in-app events

💼 Interview Questions

🎤 Mock Interview

Mock interview is powered by AI for BroadcastReceivers & System Events. Login to unlock this feature.