Communication Using A BroadcastReceiver In Android Service
Learn to implement BroadcastReceivers With Android Services to listen for custom intent actions to update Activity.

In this post I will show an example of implementing activity communication using a BroadcastReceiver in Android Service.

Β Linked below from previous posts I have shown example implementations of Android Services and BroadcastReceivers. In this example, we are putting the two implementations together.

Service Communication Using BroadcastReceiver

The Android Service will send a broadcast in its math function inside a coroutine with a custom action name. The BroadcastReceiver will listen to this custom action in the activities for further processing.

Android Service Send Custom Broadcasts To Activity

Add Service To Android Manifest

First you will need to add the Service to the Android Manifest. We do not need to add the BroadcastReceiver in this example but you could if you like. If you do, the Android system will handle the register and unregister.
        <service
            android:name=".CustomService"
            android:exported="false" />

Create A BroadcastReceiver

Next we need our BroadcastReceiver to listen for the custom intent action we specify when we register it in the activity. This will also be used when sending the broadcast from the Service.
class mBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if(intent?.action == "com.itgeek25.sampleservice.CUSTOM_ACTION"){
            Log.i("Activity", "Broadcast Received - value over 95")
        }
    }
}

Create Your Service

Ultimately I chose to keep the same math functions created in previous examples linked above. The Service will run this math function in a coroutine that will run as long as the Service is alive.
class CustomService : Service() {


        private val serviceCoroutine = CoroutineScope(Dispatchers.Default)
        private var serviceJob : Job? = null

        override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
            if(serviceJob == null){
                serviceJob = serviceCoroutine.launch {
                    while(isActive) {
                        val first = Math.floor(Math.random() * 100)
                        val second = Math.floor(Math.random() * 100)
                        val total = first + second
                        if(total > 95.0){
                            sendBroadcast(Intent("com.itgeek25.sampleservice.CUSTOM_ACTION"))
                        }
                        logi("${first} + ${second} = ${total}")
                        delay(300)
                    }
                }
            }
            return START_STICKY
        }

        override fun onBind(intent: Intent?): IBinder? {
            return null
        }

        override fun onDestroy() {
            super.onDestroy()
            logi("onDestroy")
            serviceJob?.cancel()
            serviceJob = null
        }

}

fun Service.logi(message : String){
    Log.i("CustomService", message)
}

Build Your Activity

Finally create your Activity. I have the onPause() and onResume() methods registering and unregistering the BroadcastReceiver. This will ensure we handle the BroadcastReceiver properly and the Service may continue to run in the background even when the app is not in the foreground. When the app is opened back up, the BroadcastReceiver is reregistered flawlessly and the app continues listening for the custom broadcasts.
class MainActivity : ComponentActivity() {

    var isRunning= false

    var br : mBroadcastReceiver? = null

    override fun onStop() {
        super.onStop()
        if(isRunning) {
            Intent(this@MainActivity, CustomService::class.java).apply {
                stopService(this)
            }

            isRunning= false
        }
    }

    override fun onPause() {
        super.onPause()
        if(br != null) {
            try {
                applicationContext.unregisterReceiver(br)
            } catch (e: Exception) {
                e.message?.let { Log.e("Unregister Receiver", it) }
            }
            br = null
        }
    }

    override fun onResume() {
        super.onResume()
        if(br == null) {
            br = mBroadcastReceiver()
            ContextCompat.registerReceiver(
                applicationContext,
                br,
                IntentFilter().also { it.addAction("com.itgeek25.sampleservice.CUSTOM_ACTION") },
                ContextCompat.RECEIVER_NOT_EXPORTED
            )
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
      ...
    }
}

onCreate To Build Your UI

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()

        setContent {

            SampleServiceTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Column(modifier = Modifier
                        .fillMaxSize()
                        .padding(innerPadding), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
                        Button(
                            onClick = {
                                Intent(this@MainActivity, CustomService::class.java).apply {
                                    startService(this)
                                }
                                isRunning= true
                            }
                        ) {
                            Text(text = "Start")
                        }

                        Button(
                            onClick = {
                                Intent(this@MainActivity, CustomService::class.java).apply {
                                    stopService(this)
                                }
                                isRunning= false
                            }
                        ) {
                            Text(text = "Stop")
                        }
                    }
                }
            }
        }
    }