Broadcast Receivers

Broadcast receivers are app components that can register for system events or app events. When an event occurs, registered broadcast receivers are notified via an Intent. For instance, if you are implementing a media app and you're interested in knowing when the user connects or disconnects a headset, register for the ACTION_HEADSET_PLUG intent action.

Use broadcast receivers to respond to messages that have been broadcast from apps or from the Android system. To create a broadcast receiver:

  1. Define a subclass of the BroadcastReceiver class and implement the onReceive() method.
  2. Register the broadcast receiver, either statically or dynamically.

These steps are described below.

Subclass a BroadcastReceiver

To create a broadcast receiver, define a subclass of the BroadcastReceiver class. This subclass is where Intent objects are delivered if they match the intent filters you register for.

Within your subclass:

  • Implement the onReceive() method, which is called when the BroadcastReceiver object receives an Intent broadcast .
  • Inside onReceive(), include any other logic that your broadcast receiver needs.

Example: Create a broadcast receiver

In this example, the myReceiver class a subclass of BroadcastReceiver. If the incoming broadcast intent has the ACTION_SHOW_TOAST action, the myReceiver class shows a toast message:

//Subclass of the BroadcastReceiver class.
private class myReceiver extends BroadcastReceiver {
   // Override the onReceive method to receive the broadcasts
   @Override
   public void onReceive(Context context, Intent intent) {
      //Check the Intent action and perform the required operation
        if (intent.getAction().equals(ACTION_SHOW_TOAST)) {
            CharSequence text = "Broadcast Received!";
            int duration = Toast.LENGTH_SHORT;

            Toast toast = Toast.makeText(context, text, duration);
            toast.show();
       }
   }
}

The onReceive() method is called when your app receives a registered Intent broadcast. The onReceive() method runs on the main thread unless it is explicitly asked to run on a different thread in the registerReceiver() method.

The onReceive() method has a timeout of 10 seconds. After 10 seconds, the Android system considers your receiver to be blocked, and the system might show the user an "application not responding" error. For this reason, you shouldn't implement long-running operations in onReceive().

In particular:

  • Don't try to show a dialog from within a BroadcastReceiver. Instead, display a notification using the NotificationManager API.
  • Don't try to bind to a service from within a BroadcastReceiver. Instead, use Context.startService() to send a command to the service.

If you need to perform a long-running operation inside BroadcastReceiver, use WorkManager to schedule a job. When you schedule a task with WorkManager, the task is guaranteed to run. WorkManager chooses the appropriate way to run your task, based on such factors as the device API level and the app state.

Register your broadcast receiver and set intent filters

There are two types of broadcast receivers:

  • Static receivers, which you register in the Android manifest file.
  • Dynamic receivers, which you register using a context.

Static receivers

Static receivers are also called manifest-declared receivers. To register a static receiver, include the following attributes inside the <receiver> element in your AndroidManifest.xml file:

  • android:name

    The value for this attribute is the fully classified name of the BroadcastReceiver subclass, including the package name. To use the package name that's specified in the manifest, prefix the subclass name with a period, for example .AlarmReceiver.

  • android:exported (optional)

    If this boolean value is set to false, other apps cannot send broadcasts to your receiver. This attribute is important for security.

  • <intent-filter>

    Include this nested element to specify the broadcast Intent actions that your broadcast receiver component is listening for.

The following code snippet shows static registration of a broadcast receiver that listens for a custom broadcast Intent with the action "ACTION_SHOW_TOAST":

  • The receiver's name is the name of the BroadcastReceiver subclass (.AlarmReceiver).
  • The receiver is not exported, meaning that no other apps can deliver broadcasts to this app.
  • The intent filter checks whether incoming intents include an action named ACTION_SHOW_TOAST, which is a custom Intent action defined within the app.
    <receiver
     android:name=".AlarmReceiver"
     android:exported="false">
     <intent-filter>
         <action android:name=    
              "com.example.myproject.intent.action.ACTION_SHOW_TOAST"/>
     </intent-filter>
    </receiver>
    
    Note: For Android 8.0 (API level 26) and higher, static receivers can't receive most implicit broadcasts. (Implicit broadcasts are broadcasts that don't target your app specifically.) Even if you register for these broadcasts in the manifest, the Android system won't deliver them to your app. However, you can still use a dynamic receiver to register for these broadcasts.

A few broadcasts, such as ACTION_BOOT_COMPLETED and ACTION_TIMEZONE_CHANGED, are excepted from this restriction. You can declare them in the manifest, no matter what the target API level.

Intent filters

An intent filter specifies the types of intents that a component can receive. When the system receives an Intent as a broadcast, it searches the broadcast receivers based on the values specified in receivers' intent filters.

To create an intent filter statically, use the <intent-filter> element in the Android manifest. An <intent-filter> element has one required element, <action>. The Android system compares the Intent action of the incoming broadcast to the filter action's android:name strings. If any of the names in the filter match the action name in the incoming broadcast, the broadcast is sent to your app.

This <intent-filter> listens for a system broadcast that's sent when the device boots up. Only Intent objects with an action named BOOT_COMPLETED match the filter:

<intent-filter>
    <action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>

If no intent filters are specified, the broadcast receiver can only be activated with an explicit broadcast Intent that specifies the component by name

Dynamic receivers

Dynamic receivers are also called context-registered receivers. You register a dynamic receiver using an application context or an Activity context. A dynamic receiver receives broadcasts as long as the registering context is valid:

  • If you use the application context to register your receiver, your app receives relevant broadcasts as long as your app is running in either the foreground or the background.
  • If you use an Activity context to register your receiver, your app receives relevant broadcasts until that Activity is destroyed.

To use the context to register your receiver dynamically:

  1. Create an IntentFilter and add the Intent actions that you want your app to listen for. You can add more than one action to the same IntentFilter object.

     IntentFilter intentFilter = new IntentFilter();
     filter.addAction(Intent.ACTION_POWER_CONNECTED);
     filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
    

    When the device power is connected or disconnected, the Android system broadcasts the Intent.ACTION_POWER_CONNECTED and Intent.ACTION_POWER_DISCONNECTED intent actions.

  2. Register the receiver by calling registerReceiver() method on the context. Pass in the BroadcastReceiver object and the IntentFilter object.

     mReceiver = new AlarmReceiver();
     this.registerReceiver(mReceiver, intentFilter);
    

    In this example the Activity context (this) is used to register your receiver. So the app will receive the broadcast as long as the Activity is running.

Local broadcasts

You must register local receivers dynamically, because static registration in the manifest is not possible for a local broadcasts.

To register a receiver for local broadcasts:

  1. Get an instance of LocalBroadcastManager by calling the getInstance() method.
  2. Call registerReceiver(), passing in the receiver and an IntentFilter object.
     LocalBroadcastManager.getInstance(this)
        .registerReceiver(mReceiver, 
               new IntentFilter(CustomReceiver.ACTION_CUSTOM_BROADCAST));
    

Unregister the receiver

To save system resources and avoid leaks, unregister dynamic receivers when your app no longer needs them, or before the Activity or app is destroyed. This is also true for local broadcast receivers, because they're registered dynamically.

To unregister a normal broadcast receiver:

  1. Call unregisterReceiver() and pass in your BroadcastReceiver object:

     unregisterReceiver(mReceiver);
    

    To unregister a local broadcast receiver:

  2. Get an instance of the LocalBroadcastManager.

  3. Call LocalBroadcastManager.unregisterReceiver() and pass in your BroadcastReceiver object:

     LocalBroadcastManager.getInstance(this)
        .unregisterReceiver(mReceiver);
    

    Where you call these unregisterReceiver() methods depends on the desired lifecycle of your BroadcastReceiver object:

  4. Sometimes the receiver is only needed when your activity is visible, for example to disable a network function when the network is not available. In these cases, register the receiver in onResume() and unregister the receiver in onPause().

  5. You can also use the onStart()/onStop() or onCreate()/onDestroy() method pairs, if they are more appropriate for your use case.

Comments

Popular posts from this blog

Android - Using KeyStore to encrypt and decrypt the data

Stack and Queue

Java Reflection API