Xamarin.Android by example: Monitoring the network status

Mobile apps are more often than not, about working offline. Even within our modern society, we're still going places were a connection is not guaranteed. But we still want our apps to work like they should.

In this post I'm going to explain to you a trick to know when you are connected or not, so you know when your app needs to go offline. <!--more--> <h2>Getting the network status</h2> The first thing you need to know, to decide whether or not you should be working offline, is the network status of the phone.

Android has a ConnectivityManager class that you can use to determine whether you are connected or not and if your network is metered. A metered network is a network that you basically have to pay for to use. This can be either a 3G network, HSDPA, UMTS, Edge, GPRS or whatever your provider has.

To use the ConnectivityManager you need to ask for it from a known Context instance. This is usually the activity or the Application.Context instance. The latter is useful when you're doing stuff outside of activities or want to abstract the logic away into a neat package.

The sample below demonstrates how you can get access to the ConnectivityManager and ask for the current network information.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class NetworkStatusMonitor
{
private NetworkState _state;
public NetworkStatusMonitor ()
{
}
public NetworkState State {
get {
UpdateNetworkStatus ();
return _state;
}
}
public void UpdateNetworkStatus() {
_state = NetworkState.Unknown;
// Retrieve the connectivity manager service
var connectivityManager = (ConnectivityManager)
Application.Context.GetSystemService (
Context.ConnectivityService);
// Check if the network is connected or connecting.
// This means that it will be available,
// or become available in a few seconds.
var activeNetworkInfo = connectivityManager.ActiveNetworkInfo;
if (activeNetworkInfo.IsConnectedOrConnecting) {
// Now that we know it's connected, determine if we're on WiFi or something else.
_state = activeNetworkInfo.Type == ConnectivityType.Wifi ?
NetworkState.ConnectedWifi : NetworkState.ConnectedData;
} else {
_state = NetworkState.Disconnected;
}
}
}
public enum NetworkState
{
Unknown,
ConnectedWifi,
ConnectedData,
Disconnected
}

Once you have the information, you can look up things like the type of network. The code in the sample determines which network we're on and if we are connected at all.

There's not much more to it, however there's one other thing I'd like to show you.

<h2>Using broadcast receivers to get updates</h2> While your app is running it can happen that the network status changes. For example, you move into a different area where there's no 3G, but there is a GPRS network available. It could mean, you don't want to sync data right now, because the bandwidth available is too low.

Wouldn't it be nice to get an update when that happens? Luckily there's a tool for that.

To get updates on network connectivity, you need to register a broadcast receiver to receive updates for this type of event. The sample below demonstrates building the basic broadcast receiver:

1
2
3
4
5
6
7
8
9
10
11
[BroadcastReceiver()]
public class NetworkStatusBroadcastReceiver: BroadcastReceiver {
public event EventHandler ConnectionStatusChanged;
public override void OnReceive (Context context, Intent intent)
{
if (ConnectionStatusChanged != null)
ConnectionStatusChanged (this, EventArgs.Empty);
}
}

Each broadcast receiver is derived from the BroadcastReceiver class and is marked with the BroadcastReceiver attribute. The attribute is there to tell the build tools that you want to include a broadcastreceiver entry in the manifest file. This makes sure that Android knows what you're about to do.

In the broadcast receiver you can do all sorts of things, as long as it doesn't have to do with the UI. If you need a user interface, you will have to start an activity and process the rest of the user interaction there.

The broadcast receiver in the sample is pretty basic. All it does is raise an event that the connectivity has changed and that's it. The reason I went with this simple approach is that I don't really need anything else. By registering the broadcast receiver strategically in my app, I can tell Android exactly when this receiver should be called and what I expect otherwise.

Setting up the broadcast receiver is done by calling RegisterReceiver on a context instance. Again you can use either the Application.Context instance or use the Activity you're currently in. It doesn't really matter where you register the receiver.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public event EventHandler NetworkStatusChanged;
public void Start ()
{
if (_broadcastReceiver != null) {
throw new InvalidOperationException (
"Network status monitoring already active.");
}
// Create the broadcast receiver and bind the event handler
// so that the app gets updates of the network connectivity status
_broadcastReceiver = new NetworkStatusBroadcastReceiver ();
_broadcastReceiver.ConnectionStatusChanged += OnNetworkStatusChanged;
// Register the broadcast receiver
Application.Context.RegisterReceiver (_broadcastReceiver,
new IntentFilter (ConnectivityManager.ConnectivityAction));
}
void OnNetworkStatusChanged (object sender, EventArgs e)
{
var currentStatus = _state;
UpdateNetworkStatus ();
if (currentStatus != _state && NetworkStatusChanged != null) {
NetworkStatusChanged (this, EventArgs.Empty);
}
}

Within the RegisterReceiver call I'm telling Android that I want to register my network status receiver. I'm also telling Android to only call the receiver when the network connectivity changes.

Notice that I bind an event to the receiver, so that I can update the local status property of my NetworkStatusMonitor component. This way, the app can always ask for a network status without incurring an extra call to get an up-to-date status. More importantly though, by abstracting away the broadcast receiver, I can reuse most of the code on iOS or Windows Phone to get network updates there too.

<h2>Cleaning up</h2> Registering broadcast receivers to get system broadcasts in your app is a powerful functionality. Please keep in mind that you need to clean up the receivers. They use up memory and battery and make your phone slower as more unneeded receivers are registered.

So please be a good citizen and use the following sample code to clean things up when your activities get suspended or killed by the OS.

1
2
3
4
5
6
7
8
9
10
11
12
13
public void Stop() {
if (_broadcastReceiver == null) {
throw new InvalidOperationException (
"Network status monitoring not active.");
}
// Unregister the receiver so we no longer get updates.
Application.Context.UnregisterReceiver (_broadcastReceiver);
// Set the variable to nil, so that we know the receiver is no longer used.
_broadcastReceiver.ConnectionStatusChanged -= OnNetworkStatusChanged;
_broadcastReceiver = null;
}

<h2>Conclusion</h2>

As you can see, working with the standard Android components in your Xamarin.Android app to build a network monitor is pretty straightforward.

I'll leave building an offline database of your app's data as an exercise for you to do yourself.

Enjoy!

avatar

Willem Meints

AI Fanatic, Technical Evangelist, Microsoft MVP