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.
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.
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.
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.
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.
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().
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.