Android Broadcasts made easy with RxAndroid

Background

A common task in an Android application is to listen to system broadcasts and perform some action. For example you may want to listen to network connectivity changes and pause or resume some network communication depending on the network state.

Normally this involves implementing a BroadcastReceiver then registering it with Context.registerReceiver and unregistering it with Context.unregisterReceiver in the appropriate life-cycle methods. While it is not a lot of code by itself, it can quickly become tiring to write and maintain if receivers are used many times throughout an application.

For this reason we can simplify the procedure significantly using a combination of Kotlin extension functions, RxAndroid and the Android Lifecycle-Aware Components library.

First steps

Our first step is to define a observeBroadcasts extension function on Context, this will allow us to use it anywhere we have a Context object available, be it in Activity or in a Service.


fun Context.observeBroadcasts(action: String): Observable<Intent> {
return observeBroadcasts(IntentFilter(action))
}
fun Context.observeBroadcasts(intentFilter: IntentFilter): Observable<Intent> {
val observable = Observable.create<Intent> { observer ->
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
observer.onNext(intent)
}
}
observer.setDisposable(Disposables.fromRunnable {
unregisterReceiver(receiver)
})
registerReceiver(receiver, intentFilter)
}
return observable
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
}

Example usage in an Activity:


private var connectivitySubscription: Disposable? = null
override fun onStart() {
super.onStart()
connectivitySubscription = observeBroadcasts(ConnectivityManager.CONNECTIVITY_ACTION)
.subscribe(this::onConnectivityChange)
}
override fun onStop() {
super.onStop()
connectivitySubscription?.dispose()
}
private fun onConnectivityChange(intent: Intent) {
val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val isConnected = connectivityManager.activeNetworkInfo?.isConnected ?: false
Log.i("MainActivity", "isConnected = $isConnected")
}

Adding lifecycle awareness

The previous example improved our code by removing the need to implement a BroadcastReceiver and hiding the registration flow behind a standard Rx Observable. We can however take one step further by utilizing the recently added LifecycleObserver interface and related methods in the Android Architecture Components.

This new subscribeToBroadcastsOnLifecycle is called only from Activity.onCreate with no further interaction necessary.


fun AppCompatActivity.subscribeToBroadcastsOnLifecycle(action: String, fn: (Intent) -> Unit) {
observeBroadcasts(action).subscribeOnLifecycle(lifecycle, fn)
}
fun <T> Observable<T>.subscribeOnLifecycle(lifecycle: Lifecycle, fn: (T) -> Unit) {
val lifecycleObserver: LifecycleObserver = object : LifecycleObserver {
private var subscription: Disposable? = null
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
subscription = subscribe(fn)
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
subscription?.dispose()
}
}
lifecycle.addObserver(lifecycleObserver)
}

Example usage in an Activity:


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
subscribeToBroadcastsOnLifecycle(ConnectivityManager.CONNECTIVITY_ACTION, this::onConnectivityChange)
}
private fun onConnectivityChange(intent: Intent) {
val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val isConnected = connectivityManager.activeNetworkInfo?.isConnected ?: false
Log.i("MainActivity", "isConnected = $isConnected")
}

End notes

  • Typical blog-code disclaimer: The code snippets above are only intended as inspiration and do not include all recommended error handling code.
  • subscribeToBroadcastsOnLifecycle currently only uses onStart and onStop but should be easy to extend to support any appropriate lifecycle method pairs.