ConnectivityLiveData
Using Android Architecture Components to provide an observable interface to our connectivity status.
Connectivity
Checking for connectivity on Android is reasonably straightforward. You get hold of an aptly named ConnectivityManager
and request some NetworkInfo
.
From a NetworkInfo
object you can also get other interesting information about the active network.
https://developer.android.com/reference/android/net/NetworkInfo
Observing old style
Trying to listen for connectivity changes is slightly more tricky and has changed over recent years.
Previously to achieve this, you would register a BroadcastReceiver
with an action of ConnectivityManager.CONNECTIVITY_ACTION
in your manifest. This would then trigger, as you might expect, when connectivity changes, giving you the callback you need.
This approach might be one of the Android development team’s top regrets. Since so many apps on the users phone make use of this feature, whenever there is a connectivity change, they all wake up to respond. This costs precious battery. That’s why, as of SDK 24, registering this BroadcastReceiver
in your manifest will mean you won’t receive this callback. If you register a BroadcastReceiver
using Context.registerReceiver()
however, and the context is still valid, you will still receive these events.
Shiny
The new approach is to use the new APIs on the ConnectivityManager
called registerNetworkCallback
and similar. These methods give you a callback into changes in connectivity.
LiveData
Using these new APIs in combination with LiveData
(from Android Architecture Components) we can create a wonderful observable class to provide this connectivity change callback.
You will see that we need an Application
to be passed in, rather than a Context
. This is because the ConnectivityManager
will keep hold of the context. Hence we need to make sure it has a valid one. This also makes it easier to use within a ViewModel
since using an AndroidViewModel
gives you access to an Application
.
We then ensure we’re not listening unnecessarily by only registering callbacks when the LiveData
is active.
Also note that in onActive()
we need to explicitly check for the current connectivity state. Since we had no callbacks registered, we won’t have been notified of any changes.
Think bigger
You may be wondering how you can listen for any other network changes, for example network type. This can be achieved by overriding more methods on NetworkCallback
, for example onCapabilitiesChanged()
. See the documentation for more details.
https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback
Then you can make use of the method ConnectivityManager.getNetworkInfo()
to retrieve the familiar NetworkInfo
object.
This allows you to determine many things, including network type by calling NetworkInfo.getType()
.
https://developer.android.com/reference/android/net/NetworkInfo.html#getType()
Testing
To test this class, we can write an Android instrumented as follows:
It needs to be an instrumented test since NetworkRequest.Builder.build()
is part of the Android framework. This means it isn’t accessible from a normal JUnit test.
Note we use nhaarman/mockito-kotlin to help with testing our Kotlin code.
Helpful links
https://developer.android.com/training/monitoring-device-state/connectivity-monitoring
https://developer.android.com/reference/android/net/ConnectivityManager
https://developer.android.com/topic/libraries/architecture/
Previous Post
Writing an API — a mobile developer story
Originally published at www.brightec.co.uk.