In this post I will demonstrate how to implement an Android BroadcastReceiver to listen for custom actions.
Generally, most common uses for Android BroadcastReceivers are to notify your app that some action has changed on the device.
In another case, maybe your app relies on specific device features to be enabled. If your app makes a request to pair with a device via bluetooth, it is important to ensure that bluetooth is turned on. If it is off, then you could create a BroadcastReceiver to monitor when bluetooth is enabled so your app can move forward with its functionality.
With that being said, you are not limited to system features for the BroadcastReceiver to listen to. You can create a BroadcastReceiver to listen for custom actions for further processing in your app.
Check out the link below from a previous post for more about BroadcastReceivers. It demonstrates how to implement a basic Android BroadcastReceiver.
Android BroadcastReceiver To Listen For Custom Actions
Code
Create Your BroadcastReceiver
class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if(intent?.action == "com.itgeek25.samplebroadcastreceiver.custom_action"){
intent.getStringExtra("message")?.let { DataRepo.updateState(it) }
}
}
}
Implement A Singleton Repository
object DataRepo {
private val _text: MutableStateFlow<String> = MutableStateFlow<String>("")
val text: StateFlow<String> = _text.asStateFlow()
fun updateState(state : String){
_text.value = state
}
}
Monitor UI State Updates Using A ViewModel
class ViewModel : ViewModel() {
val state: StateFlow<String> = DataRepo.text
}
class ViewModelFactory : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return if(modelClass.isAssignableFrom(com.itgeek25.samplebroadcastreceiver.viewmodel.ViewModel::class.java)){
com.itgeek25.samplebroadcastreceiver.viewmodel.ViewModel() as T
} else {
throw IllegalArgumentException("ViewModel Not Found!!")
}
}
}
Build Your MainActivity
class MainActivity : ComponentActivity() {
lateinit var viewModel: ViewModel
var mBroadcastReceiver = MyReceiver()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val factory = ViewModelFactory()
viewModel = ViewModelProvider(
this,
factory
)[ViewModel::class.java]
ContextCompat.registerReceiver(applicationContext, mBroadcastReceiver, IntentFilter().also { it.addAction("com.itgeek25.samplebroadcastreceiver.custom_action") },
ContextCompat.RECEIVER_NOT_EXPORTED)
setContent {
var text by remember { mutableStateOf("") }
val br_text = viewModel.state.collectAsStateWithLifecycle().value
SampleBroadcastReceiverTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Column(modifier = Modifier
.fillMaxSize()
.padding(innerPadding),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally) {
Text(
modifier = Modifier,
style = MaterialTheme.typography.titleLarge,
text = br_text,
)
TextField(
value = text,
onValueChange = {
text = it
},
placeholder = {
Text(text = "Enter your message")
})
Button(onClick = {
sendBroadcast(Intent("com.itgeek25.samplebroadcastreceiver.custom_action").also {
it.putExtra("message", text)
})
}) {
Text("Click To Send Broadcast")
}
}
}
}
}
}
override fun onStop() {
super.onStop()
if(mBroadcastReceiver != null){
unregisterReceiver(mBroadcastReceiver)
}
}
}
Bonus
There is an alternative way to register your BroadcastReceiver in your app. You can add it to your AndroidManifest.xml. The benefit of doing it this way will be that Android will take care of register / unregister of the BroadcastReceiver for the app.
Add BroadcastReceiver To Your AndroidManifest.XML
You just need to add the reference to the class as a receiver object inside the application tags.
<receiver android:name=".broadcastreceiver.MyReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.itgeek25.samplebroadcastreceiver.custom_action" />
</intent-filter>
</receiver>
Edit The MainActivity
Lastly in this approach you will not need to add references to the BroadcastReceiver class. The only thing that is necessary is setting the class of the BroadcastReceiver in the Intent being passed to from the sendBroadcast() method.
class MainActivity : ComponentActivity() {
lateinit var viewModel: ViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val factory = ViewModelFactory()
viewModel = ViewModelProvider(
this,
factory
)[ViewModel::class.java]
setContent {
var text by remember { mutableStateOf("") }
val br_text = viewModel.state.collectAsStateWithLifecycle().value
SampleBroadcastReceiverTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Column(modifier = Modifier
.fillMaxSize()
.padding(innerPadding),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally) {
Text(
modifier = Modifier,
style = MaterialTheme.typography.titleLarge,
text = br_text,
)
TextField(
value = text,
onValueChange = {
text = it
},
placeholder = {
Text(text = "Enter your message")
})
Button(onClick = {
sendBroadcast(Intent("com.itgeek25.samplebroadcastreceiver.custom_action").also {
it.putExtra("message", text)
it.setClass(this@MainActivity, MyReceiver::class.java)
})
}) {
Text("Click To Send Broadcast")
}
}
}
}
}
}
}