Notes: 20. Communicate Using BroadcastReceivers
The student materials have been reviewed and are updated as of SEPTEMBER 2022.
Previously you implemented a foreground service, which showed a notification. But you didn’t have a way to communicate back to the UI, that the service has finished, and that the images have been synchronized. To implement such behavior, you need to use BroadcastReceivers.
BroadcastReceivers are special components in Android, that communicate using Intents, and special actions. Each receiver can register and listen for a certain set of actions, and it can decide which actions it’s going to react to, and how.
So what happens is you register a receiver to process certain messages, and give it a callback to send events through. Then you start your services, or other components which do some work.
After those components finish their work, they broadcast an intent with the selected action, and your receivers pick it up. Then the receiver notifies your UI component, through the callback. Pretty simple and effective!
Let’s implement a receiver, to communicate from our service!
Start off by creating a new class named SynchronizeImagesReceiver, and adding the following code:
const val ACTION_IMAGES_SYNCHRONIZED = "images_synchronized"
class SynchronizeImagesReceiver(
private inline val onImagesSynchronized: () -> Unit) : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == ACTION_IMAGES_SYNCHRONIZED) {
onImagesSynchronized()
}
}
}
The class is very small, and does only one thing. When it receives an intent with the action you’ve declared, it invokes a callback function! You’ll see how this will help once a few more pieces are in place!
Next, head over to the SynchronizeImagesService, and change the code which fetches images, to the next:
private fun fetchImages() {
GlobalScope.launch {
val result = remoteApi.getImages()
if (result is Success) {
val imagesArray = result.data.map { it.imagePath }.toTypedArray()
FileUtils.queueImagesForDownload(applicationContext, imagesArray)
stopForeground(true)
sendBroadcast(Intent().apply {
action = ACTION_IMAGES_SYNCHRONIZED
})
}
}
}
Not only will this snippet of code fetch images, but it will also stop the foreground notification when it’s done, and it will send a broadcast with the action defined in the receiver! What will happen here is that once images are downloaded, the notification will be removed, and the service will stop being in the foreground.
After which the broadcast it sends will trigger the receiver, and show a message to the user! Finally, head over to the MainActivity, and add the following few snippets of code:
private val receiver by lazy {
SynchronizeImagesReceiver {
toast("Images synchronized!")
}
}
You first create a receiver value, with the callback that toasts a message “Images synchronized”. Next:
registerReceiver(receiver, IntentFilter().apply {
addAction(ACTION_IMAGES_SYNCHRONIZED)
})
You register the receiver, with an intent filter that listens to the action you defined. And finally:
unregisterReceiver(receiver)
You have to unregister the receiver, once the activity stops. That’s it! Run the project to check out the changes, and see if your message appears! :]