Read network state

Android enables apps to learn about dynamic changes in connectivity. Use the following classes to track and respond to connectivity changes:

  • ConnectivityManager tells your app about the state of connectivity in the system.
  • The Network class represents one of the networks that the device is connected to. You can use the Network object as a key to gather information about the network with ConnectivityManager or to bind sockets on the network. When the network disconnects, the Network object stops being usable. Even if the device later reconnects to the same appliance, a new Network object represents the new network.
  • The LinkProperties object contains information about the link for a network, such as the list of DNS servers, local IP addresses, and network routes installed for the network.
  • The NetworkCapabilities object contains information about properties of a network, such as the transports (Wi-Fi, mobile, Bluetooth) and what the network is capable of. For example, you can query the object to determine whether the network is capable of sending MMS, is behind a captive portal, or is metered.

Apps interested in the immediate state of connectivity at any given time can call ConnectivityManager methods to find out what kind of network is available. These methods are helpful for debugging and to occasionally review a snapshot of connectivity available at any given time.

However, the synchronous ConnectivityManager methods don't tell your app about anything happening after a call, so they don't let you update your UI. They also can't adjust app behavior based on the network disconnecting or when the network capabilities change.

Connectivity can change at any time, and most apps need to have an always-fresh, up-to-date view of the state of networking on the device. Apps can register a callback with ConnectivityManager to be alerted to changes that the app cares about. Using the callback, your app can react immediately to any relevant change in connectivity, without having to resort to expensive polling that might miss fast updates.

Using NetworkCallback and other ways of finding out about the connectivity state of the device doesn't require any particular permission. However, some networks are subject to specific permissions. For example, there might be restricted networks not available to apps. Binding to a background network requires the CHANGE_NETWORK_STATE permission. And some calls might need specific permissions to run. Refer to the specific documentation for each call for details.

Get instantaneous state

An Android-powered device can maintain many connections at the same time. To get information about the current network state, first obtain an instance of ConnectivityManager:

Kotlin

val connectivityManager = getSystemService(ConnectivityManager::class.java)

Java

ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class);

Next, use this instance to get a reference to the current default network for your app:

Kotlin

val currentNetwork = connectivityManager.getActiveNetwork()

Java

Network currentNetwork = connectivityManager.getActiveNetwork();

With a reference to a network, your app can request information about it:

Kotlin

val caps = connectivityManager.getNetworkCapabilities(currentNetwork)
val linkProperties = connectivityManager.getLinkProperties(currentNetwork)

Java

NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(currentNetwork);
LinkProperties linkProperties = connectivityManager.getLinkProperties(currentNetwork);

For more useful functionality, register a NetworkCallback. For more information about registering network callbacks, see Listen to network events.

NetworkCapabilities and LinkProperties

The NetworkCapabilities and LinkProperties objects provide information about all attributes that the system knows about a network.

The LinkProperties object knows about the routes, link addresses, interface name, proxy info (if any), and DNS servers. Call the relevant method on the LinkProperties object to retrieve the information you need.

The NetworkCapabilities object encapsulates information about the network transports and their capabilities.

A transport is an abstraction of a physical medium over which a network operates. Common examples of transports are Ethernet, Wi-Fi, and mobile. VPNs and Peer-to-Peer Wi-Fi can also be transports. On Android, a network can have multiple transports at the same time. An example of this is a VPN operating over both Wi-Fi and mobile networks. The VPN has the Wi-Fi, mobile, and VPN transports. To find out if a network has a particular transport, use the NetworkCapabilities.hasTransport(int) method with one of the NetworkCapabilities.TRANSPORT_* constants.

A capability describes a property of the network. Example capabilities include MMS, NOT_METERED, and INTERNET. A network with the MMS capability can send and receive Multimedia Messaging Service messages, and a network without this capability can't. A network with the NOT_METERED capability doesn't bill the user for data. Your app can check for appropriate capabilities by using the NetworkCapabilities.hasCapability(int) method with one of the NetworkCapabilities.NET_CAPABILITY_* constants.

The most-useful NET_CAPABILITY_* constants include:

  • NET_CAPABILITY_INTERNET: indicates that the network is set up to access the internet. This is about setup and not actual ability to reach public servers. For example, a network can be set up to access the internet but be subject to a captive portal.

    A carrier's mobile network typically has the INTERNET capability, while a local P2P Wi-Fi network typically doesn't. For actual connectivity, see NET_CAPABILITY_VALIDATED.

  • NET_CAPABILITY_NOT_METERED: indicates that the network isn't metered. A network is classified as metered when the user is sensitive to heavy data usage on that connection due to monetary costs, data limitations, or battery performance issues.

  • NET_CAPABILITY_NOT_VPN: indicates that the network isn't a virtual private network.

  • NET_CAPABILITY_VALIDATED: indicates that the network provides actual access to the public internet when it is probed. A network behind a captive portal or a network that doesn't provide domain name resolution doesn't have this capability. This is the nearest the system can tell about a network actually providing access, although a validated network can still, in principle, be subject to IP-based filtering or suffer sudden losses of connectivity due to issues such as poor signal.

  • NET_CAPABILITY_CAPTIVE_PORTAL: indicates that the network has a captive portal when it is probed.

There are other capabilities that more specialized apps might be interested in. For more information, read the parameter definitions in NetworkCapabilities.hasCapability(int).

The capabilities of a network can change at any time. When the system detects a captive portal, it shows a notification inviting the user to log in. While this is ongoing, the network has the NET_CAPABILITY_INTERNET and NET_CAPABILITY_CAPTIVE_PORTAL capabilities but not the NET_CAPABILITY_VALIDATED capability.

When the user takes action and logs in to the captive portal page, the device becomes able to access the public internet and the network gains the NET_CAPABILITY_VALIDATED capability and loses the NET_CAPABILITY_CAPTIVE_PORTAL capability.

Likewise, the transports of a network can change dynamically. For example, a VPN can reconfigure itself to use a faster network that just came up, like switching from mobile to Wi-Fi for its underlying network. In this case, the network loses the TRANSPORT_CELLULAR transport and gains the TRANSPORT_WIFI transport, while keeping the TRANSPORT_VPN transport.

Listen to network events

To find out about network events, use the NetworkCallback class together with ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback) and ConnectivityManager.registerNetworkCallback(NetworkCallback). These two methods serve different purposes.

All Android apps have a default network, which is determined by the system. The system typically prefers unmetered networks to metered ones and faster networks to slower ones.

When an app issues a network request, such as with HttpsURLConnection, the system satisfies this request using the default network. Apps can send traffic on other networks, too. For more information, see the section about additional networks.

The network that is set as the default network can change at any time during the lifetime of an app. A typical example is the device coming within range of a known, active, unmetered, and faster-than-mobile Wi-Fi access point. The device connects to this access point and switches the default network for all apps to the new Wi-Fi network.

When a new network becomes the default, any new connection the app opens uses this network. At some point later, all remaining connections on the previous default network are forcefully terminated. If it is important for the app to know when the default network changes, it registers a default network callback as follows:

Kotlin

connectivityManager.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
    override fun onAvailable(network : Network) {
        Log.e(TAG, "The default network is now: " + network)
    }

    override fun onLost(network : Network) {
        Log.e(TAG, "The application no longer has a default network. The last default network was " + network)
    }

    override fun onCapabilitiesChanged(network : Network, networkCapabilities : NetworkCapabilities) {
        Log.e(TAG, "The default network changed capabilities: " + networkCapabilities)
    }

    override fun onLinkPropertiesChanged(network : Network, linkProperties : LinkProperties) {
        Log.e(TAG, "The default network changed link properties: " + linkProperties)
    }
})

Java

connectivityManager.registerDefaultNetworkCallback(new ConnectivityManager.NetworkCallback() {
    @Override
    public void onAvailable(Network network) {
        Log.e(TAG, "The default network is now: " + network);
    }

    @Override
    public void onLost(Network network) {
        Log.e(TAG, "The application no longer has a default network. The last default network was " + network);
    }

    @Override
    public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
        Log.e(TAG, "The default network changed capabilities: " + networkCapabilities);
    }

    @Override
    public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
        Log.e(TAG, "The default network changed link properties: " + linkProperties);
    }
});

When a new network becomes the default, the app receives a call to onAvailable(Network) for the new network. Implement onCapabilitiesChanged(Network,NetworkCapabilities), onLinkPropertiesChanged(Network,LinkProperties), or both to react appropriately to changes in connectivity.

For a callback registered with registerDefaultNetworkCallback(), onLost() means the network has lost the status of being the default network. It might be disconnected.

Although you can learn about the transports that the default network is using by querying NetworkCapabilities.hasTransport(int), this is a poor proxy for the bandwidth or meteredness of the network. Your app can't assume Wi-Fi is always unmetered and always supplies better bandwidth than mobile.

Instead use NetworkCapabilities.getLinkDownstreamBandwidthKbps() to measure bandwidth, and NetworkCapabilites.hasCapability(int) with NET_CAPABILITY_NOT_METERED arguments to determine meteredness. For more information, see the section about NetworkCapabilities and LinkProperties.

By default, the callback methods are called on the connectivity thread of your app, which is a separate thread used by ConnectivityManager. If your implementation of the callbacks needs to do any longer work, call them on a separate worker thread by using the variant ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback, Handler).

Unregister your callback when you have no use for it anymore by calling ConnectivityManager.unregisterNetworkCallback(NetworkCallback). Your main activity's onPause() is a good place to do this, especially if you register the callback in onResume().

Additional networks

Although the default network is the only relevant network for most apps, some apps might be interested in other available networks. To find out about these, apps build a NetworkRequest matching their needs and call ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback).

The process is similar to listening to a default network. However, although there might only be one default network that applies to an app at any given time, this version lets your app see all the available networks simultaneously, so a call to onLost(Network) means the network has disconnected for good, not that it's not the default anymore.

The app builds a NetworkRequest to inform ConnectivityManager of what kind of networks it wants to listen to. The following example shows how to build a NetworkRequest for an app that is only interested in unmetered internet connections:

Kotlin

val request = NetworkRequest.Builder()
  .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
  .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
  .build()

connectivityManager.registerNetworkCallback(request, myNetworkCallback)

Java

NetworkRequest request = new NetworkRequest.Builder()
  .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
  .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
  .build();

connectivityManager.registerNetworkCallback(request, myNetworkCallback);

This means your app hears about all changes concerning any unmetered network on the system.

As for the default network callback, there is a version of registerNetworkCallback(NetworkRequest, NetworkCallback, Handler) that accepts a Handler so it doesn't load the Connectivity thread of your app.

Call ConnectivityManager.unregisterNetworkCallback(NetworkCallback) when the callback isn't relevant anymore. An app can concurrently register multiple network callbacks.

For convenience, the NetworkRequest object contains the common capabilities most apps need, including the following:

When writing your app, check the defaults to see whether they match your use case, and clear them if you want your app to be notified about networks that don't have these capabilities. On the other hand, add capabilities to avoid being called for any connectivity change in networks that your app doesn't interact with.

For example, if your app needs to send MMS messages, add NET_CAPABILITY_MMS to the NetworkRequest to avoid being told about all the networks that can't send MMS messages. Add TRANSPORT_WIFI_AWARE if your app is only interested in P2P Wi-Fi connectivity. NET_CAPABILITY_INTERNET and NET_CAPABILITY_VALIDATED are helpful if you are interested in the ability to transfer data with a server on the internet.

Sample callback sequence

This section describes the sequence of callbacks an app might get if it registers both a default callback and a regular callback on a device that has mobile connectivity. In this example, the device connects to a good Wi-Fi access point, then disconnects from it. The example also assumes the device has the Mobile data always on setting enabled.

The timeline is as follows:

  1. When the app calls registerNetworkCallback(), the callback immediately receives calls from onAvailable(), onNetworkCapabilitiesChanged(), and onLinkPropertiesChanged() for the mobile network, because only that network is available. If another network is available, the app also receives callbacks for the other network.

    State diagram showing the register network callback event and the callbacks triggered by the event
    Figure 1. App state after calling registerNetworkCallback().

  2. Then, the app calls registerDefaultNetworkCallback(). The default network callback starts receiving calls to onAvailable(), onNetworkCapabilitiesChanged(), and onLinkPropertiesChanged() for the mobile network, because the mobile network is the default network. If another, non-default network is up, the app can't receive calls for the non-default network.

    State diagram showing register the default network callback event and the
callbacks triggered by the event
    Figure 2. App state after registering a default network.

  3. Later, the device connects to an (unmetered) Wi-Fi network. The regular network callback receives calls to onAvailable(), onNetworkCapabilitiesChanged(), and onLinkPropertiesChanged() for the Wi-Fi network.

    State diagram showing the callbacks triggered when the app connects to a
new network
    Figure 3. App state after connecting to an unmetered Wi-Fi network.

  4. At this point, it is possible the Wi-Fi network takes a while to validate. In this case, the onNetworkCapabilitiesChanged() calls for the regular network callback don't include capability NET_CAPABILITY_VALIDATED. After a short time, it receives a call to onNetworkCapabilitiesChanged(), where the new capabilities include NET_CAPABILITY_VALIDATED. In most cases, the validation is very quick.

    When the Wi-Fi network validates, the system prefers it to the mobile network, mainly because it is unmetered. The Wi-Fi network becomes the default network, so the default network callback receives a call to onAvailable(), onNetworkCapabilitiesChanged(), and onLinkPropertiesChanged() for the Wi-Fi network. The mobile network goes to the background, and the regular network callback receives a call to onLosing() for the mobile network.

    Because this example assumes mobile data is always on for this device, the mobile network never disconnects. If the setting is turned off, then after a while the mobile network disconnects, and the regular network callback receives a call to onLost().

    State diagram showing the callbacks triggered when a Wi-Fi network
connection validates
    Figure 4. App state after Wi-Fi network validates.

  5. Later still, the device suddenly disconnects from Wi-Fi, because it went out of range. Because the Wi-Fi disconnects, the regular network callback receives a call to onLost() for Wi-Fi. Because mobile is the new default network, the default network callback receives calls to onAvailable(), onNetworkCapabilitiesChanged(), and onLinkPropertiesChanged() for the mobile network.

    State diagram showing the callbacks triggered when a Wi-Fi network
connection is lost
    Figure 5. App state after disconnecting from Wi-Fi network.

If the Mobile data always on setting is turned off, then when Wi-Fi disconnects the device tries to reconnect to a mobile network. The picture is similar, but with a short additional delay for the onAvailable() calls, and the regular network callback also receives calls to onAvailable(), onNetworkCapabilitiesChanged(), and onLinkPropertiesChanged() because mobile becomes available.

Restrictions on the use of the network for data transfer

Being able to see a network with a network callback doesn't mean your app can use the network for data transfer. Some networks don't provide internet connectivity, and some networks might be restricted to privileged apps. To check for internet connectivity, see NET_CAPABILITY_INTERNET and NET_CAPABILITY_VALIDATED.

Use of background networks is also subject to permission checks. If your app wants to use a background network, it needs the CHANGE_NETWORK_STATE permission.

Apps with this permission let the system try to bring up a network that isn't up, such as the mobile network when the device is connected to a Wi-Fi network. Such an app calls ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback) with a NetworkCallback to be called when the network is brought up.