Android Development and ConnectivityDataLive
Written by Alistair Sykes
Jun 28, 2018

ConnectivityLiveData

Our Android development team look at 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.

https://developer.android.com/reference/android/net/ConnectivityManager.html#registerNetworkCallback(android.net.NetworkRequest,%20android.net.ConnectivityManager.NetworkCallback)

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.

https://developer.android.com/reference/android/net/ConnectivityManager.html#getNetworkInfo(android.net.Network)

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

Top