GetActiveNetworkInfo Does Not Work as Expected

If you are developing for Android devices, probably you faced the problem where you should check if a user has access to Internet. The general use case is when a user has access to Internet you would call an API and update the local database, but if a user doesn’t have access to Internet, you would skip the API call and read from local database?

Google thought about that use case so they created the method inside Android framework getActiveNetworkInfo with which you can check if a device is connected to the network interface or not.

Easy, isn’t it? I just wrote this method and whether I have to check if I have to call an API or just load local data, I would call this method.

public static boolean isNetworkAvailable() {  
    ConnectivityManager connectivityManager 
          = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

Does it work always? In most cases yes, but let’s check what official documentation is saying.

Returns details about the currently active default data network. When connected, this network is the default route for outgoing connections. You should always check isConnected() before initiating network traffic. This may return null when there is no default network.

If we read that more carefully we will see that this method is just telling us if the device is connected to the network interface. The fact is that if the device is connected to the network interface, it does not mean interface is connected to the internet (public network).

Note that having an active network interface doesn’t guarantee that a particular networked service is available. Networks issues, server downtime, low signal, captive portals, content filters and the like can all prevent your app from reaching a server. For instance you can’t tell for sure if your app can reach Twitter until you receive a valid response from the Twitter service. Stack Overflow

This edge use case is often because many times the device is connected to WIFI but without public internet access. So if you have a method for checking internet connection before doing API call, you will try to call the server because the device thinks it has Internet connection.

On Stack Overflow, someone said you can ping Google DNS to be sure there is an Internet connection, so the method would look like this.

public static boolean isNetworkAvailable () {

    Runtime runtime = Runtime.getRuntime();
    try {

        Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
        int     exitValue = ipProcess.waitFor();
        return (exitValue == 0);

    } catch (IOException e){
          e.printStackTrace();
    } catch (InterruptedException e){
          e.printStackTrace();
    }
    return false;
}

When you run a process within your app, you only are granting the app’s limited permissions to the process. So if ping requires root level permission (on the specific device), that may also be the reason why it does not work. It is ultimately up to the OEM of how they customized Android. Stack Overflow

This method works and it’s fast. The problem with it is that the method does not work on every device. On devices where the method does not work, it will return false so we will think there is no Internet connection.

To avoid this problem we decide to write a method that will ping google via HttpURLConnection. That way it should work on every device:

public static boolean isNetworkAvailable () {  
    boolean success = false;
    try {
        URL url = new URL("https://google.com");
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setConnectTimeout(10000);
        connection.connect();
        success = connection.getResponseCode() == 200;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return success;
}

With this approach we still have one problem, is not the same as in method before but the problem is the problem. Can you notice? If we call this, our method will fetch a full Google site, just in order to check for the connection. It’s not an efficient way, so we made a new one.

public static boolean isNetworkAvailable (Context context) {  
    if (connectedToTheNetwork(context)) {
        try {
            HttpURLConnection urlc = (HttpURLConnection) 
                (new URL("http://clients3.google.com/generate_204")
                .openConnection());
            urlc.setRequestProperty("User-Agent", "Android");
            urlc.setRequestProperty("Connection", "close");
            urlc.setConnectTimeout(1500); 
            urlc.connect();
            return (urlc.getResponseCode() == 204 &&
                        urlc.getContentLength() == 0);
        } catch (IOException e) {
            Log.e(TAG, "Error checking internet connection", e);
        }
    } else {
        Log.d(TAG, "No network available!");
    }
    return false;
}

Using the method above, we will not have to fetch the entire Google page so it’s much better than the method before.

This is a rewrite of my old article that I published on medium a few years ago: What if your Android user doesn’t have access to the Internet

Either you have your own idea and you want to consult with our experts or you just want to share your opinion, feel free to Contact Us
Alen Huskanović
Alen Huskanović
A guy with huge interests in technology and sharing his knowledge with interested people. He is a co-founder of a digital agency Async Labs where he was helping companies all around the world to become present on the Internet with digital marketing strategies. Using growth hacking actions he had a couple of successfully campaigns where he achieves an impressive number of followers on different social media channels.
Lets's do some work
+1
Share
Tweet
Share
Pin