Android Broadcast Intents and Broadcast Receivers using Kotlin

In addition to providing a mechanism for launching application activities, intents are also used as a way to broadcast system wide messages to other components on the system like Broadcast Intents and Broadcast Receivers.

You can find article for Java language here.

Broadcast intents are Intent objects that are broadcast via a call to the sendBroadcast(), sendStickyBroadcast() or sendOrderedBroadcast() methods of the Activity class. In addition to providing a messaging and event system between application components, broadcast intents are also used by the Android system to notify interested applications about key system events (such as the external power supply or headphones being connected or disconnected).

When a broadcast intent is created, it must include an action string in addition to optional data and a category string. As with standard intents, data is added to a broadcast intent using key-value pairs in conjunction with the putExtra() method of the intent object. The optional category string may be assigned to a broadcast intent via a call to the addCategory() method.

The action string, which identifies the broadcast event, must be unique and typically uses the application’s package name syntax. For example, the following code fragment creates and sends a broadcast intent including a unique action string and data:

val intent = Intent()
intent.action = "me.proft.Broadcast"
intent.putExtra("year", 2019)
sendBroadcast(intent)

An application listens for specific broadcast intents by registering a broadcast receiver. Broadcast receivers are implemented by extending the Android BroadcastReceiver class and overriding the onReceive() method. The broadcast receiver may then be registered, either within code (for example within an activity), or within a manifest file. Part of the registration implementation involves the creation of intent filters to indicate the specific broadcast intents the receiver is required to listen for. This is achieved by referencing the action string of the broadcast intent. When a matching broadcast is detected, the onReceive() method of the broadcast receiver is called, at which point the method has 5 seconds within which to perform any necessary tasks before returning. It is important to note that a broadcast receiver does not need to be running all the time. In the event that a matching intent is detected, the Android runtime system will automatically start up the broadcast receiver before calling the onReceive() method.

The following code outlines a template Broadcast Receiver subclass:

class MyReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        throw UnsupportedOperationException("Not yet implemented")
    }
}

When registering a broadcast receiver within a manifest file, a <receiver> entry must be added for the receiver. The following example manifest file registers the above example broadcast receiver:

<manifest ...>
    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name" >
        <receiver android:name="MyReceiver" >
        </receiver>
    </application>
</manifest>

When running on versions of Android older than Android 8.0, the intent filters associated with a receiver can be placed within the receiver element of the manifest file as follows:

<receiver android:name="MyReceiver" >
    <intent-filter>
        <action android:name="com.example.Broadcast" >
        </action>
    </intent-filter>
</receiver>

On Android 8.0 or later, the receiver must be registered in code using the registerReceiver() method of the Activity class together with an appropriately configured IntentFilter object:

val filter = IntentFilter()
filter.addAction("com.example.Broadcast")
val receiver: MyReceiver = MyReceiver()
registerReceiver(receiver, filter)

When a broadcast receiver registered in code is no longer required, it may be unregistered via a call to the unregisterReceiver() method of the activity class, passing through a reference to the receiver object as an argument. For example, the following code will unregister the above broadcast receiver:

unregisterReceiver(receiver)

It is important to keep in mind that some system broadcast intents can only be detected by a broadcast receiver if it is registered in code rather than in the manifest file. Check the Android Intent class documentation for a detailed overview of the system broadcast intents and corresponding requirements online.

Creating and Sending the Broadcast Intent

So, launch Android Studio and create a new project. Following is layout for testing app.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:padding="5dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send broadcast"
        android:onClick="broadcastIntent"/>

</RelativeLayout>

It is now time to implement the code to send the broadcast intent.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    fun broadcastIntent(view: View) {
       val intent = Intent()
       intent.action = "me.proft.sendbroadcast"
       intent.flags = Intent.FLAG_INCLUDE_STOPPED_PACKAGES
       sendBroadcast(intent)
    }
}

Creating the Broadcast Receiver

In order to create the broadcast receiver, a new class needs to be created which subclasses the BroadcastReceiver superclass. Within the Project tool window, navigate to app -> java and right-click on the package name. From the resulting menu, select the New -> Other -> Broadcast Receiver menu option, name the class MyReceiver and make sure the Exported and Enabled options are selected. These settings allow the Android system to launch the receiver when needed and ensure that the class can receive messages sent by other applications on the device. With the class configured, click on Finish.

Once created, Android Studio will automatically load the new MyReceiver.kt class file into the editor. Modify the code so that it reads as follows

class MyReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Toast.makeText(context, "Broadcast Intent Detected.",
                Toast.LENGTH_LONG).show()
    }
}

Registering the Broadcast Receiver

The project needs to publicize the presence of the broadcast receiver and must include an intent filter to specify the broadcast intents in which the receiver is interested. When the BroadcastReceiver class was created in the previous section, Android Studio automatically added a <receiver> element to the manifest file. All that remains, therefore, is to add code within the MainActivity.kt file to create an intent filter and to register the receiver:

class MainActivity : AppCompatActivity() {
    var receiver: BroadcastReceiver? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_send_broadcast)
        configureReceiver()
    }

    private fun configureReceiver() {
        val filter = IntentFilter()
        filter.addAction("me.proft.sendbroadcast")
        receiver = MyReceiver()
        registerReceiver(receiver, filter)
    }
}

It is also important to unregister the broadcast receiver when it is no longer needed:

override fun onDestroy() {
    super.onDestroy()
    unregisterReceiver(receiver)
}

So, broadcast intents are a mechanism by which an intent can be issued for consumption by multiple components on an Android system. Broadcasts are detected by registering a Broadcast Receiver which, in turn, is configured to listen for intents that match particular action strings. In general, broadcast receivers remain dormant until woken up by the system when a matching intent is detected. Broadcast intents are also used by the Android system to issue notifications of events such as a low battery warning or the connection or disconnection of external power to the device.