Created
January 5, 2021 04:22
-
-
Save virendersran01/8eaac7dfc9ff9757523c986aac138ca7 to your computer and use it in GitHub Desktop.
Checking Active Internet Connection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Implementing Internet Connectivity Checker in Android Apps | |
Amr Salah | |
Amr Salah | |
4 days ago·5 min read | |
Image for post | |
Photo by Rami Al-zayat on Unsplash | |
Working on an Android chat app? social media app? or any other internet-based app that you want to check if there is an internet connection in order to continue a process or even notify the user about their network state? This guide comes to the rescue! | |
You may say: “Hey! There is already an API which gets this job done.” | |
Yes, there is! Well, although Android SDK provides API that you can use to get network state of user’s device like ConnectivityManager, it does not actually check whether there is an active internet connection. Concretely, try establishing a hotspot from mobile device “A” but do not turn on mobile data or wifi, then connect mobile device “B” to that hotspot of “A”. | |
Using device “B”, when you try to search, say, on Google this won’t work as there is no internet connection although you are connected to a network. ConnectivityManager APIs work the same. They just tell whether you are connected to a network or not — regardless of having an active internet connection or not. | |
So, the bottom line is: | |
“How do we check if there is an active internet connection?” | |
Basically, we can ping or connect to any server to see whether this ping or connection is successful or not. | |
If you have your own backend server, you may prefer to try to connect your app to the server to make sure that the device has an internet connection and your server is not down at the same time. | |
We can also connect to Google’s servers as they are unlikely to be down (or for a long time). | |
To optimize our class implementation (we’ll call it NetworkConnectivity), it’s good to check a device’s network connection using ConnectivityManager so that if wifi or mobile data is turned off or even wifi is turned on but there is no network the device is connected to, we don’t have to make requests to any servers. | |
Enough talk! | |
First of all, add internet and network state permissions in your app manifest: | |
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | |
<uses-permission android:name="android.permission.INTERNET" /> | |
Now, create a function to check network availability using ConnectivityManager: | |
private boolean isNetworkAvailable() { | |
ConnectivityManager cm = (ConnectivityManager) context | |
.getSystemService(Context.CONNECTIVITY_SERVICE); | |
if (cm == null) return false; | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { | |
NetworkCapabilities cap = cm | |
.getNetworkCapabilities(cm.getActiveNetwork()); | |
if (cap == null) return false; | |
return cap.hasCapability( | |
NetworkCapabilities.NET_CAPABILITY_INTERNET | |
); | |
} else if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){ | |
Network[] networks = cm.getAllNetworks(); | |
for (Network n : networks) { | |
NetworkInfo nInfo = cm.getNetworkInfo(n); | |
if (nInfo != null && nInfo.isConnected()) return true; | |
} | |
} else { | |
NetworkInfo[] networks = cm.getAllNetworkInfo(); | |
for (NetworkInfo nInfo : networks) { | |
if (nInfo != null && nInfo.isConnected()) return true; | |
} | |
} | |
return false; | |
} | |
Here we used getAllNetworkInfo() to return an array of objects of all networks and then we check whether any of them is connected. | |
But this method is deprecated since API 23. For later APIs, we used getAllNetworks() which is added in API 21. But yea, getNetworkInfo() is also deprecated since API 29 :) | |
Back to our business | |
To ping Google’s server, basically, we can do that with a few lines of code: | |
boolean isConnected; | |
Process process = Runtime.getRuntime().exec(“/system/bin/ping -c 1 8.8.8.8”); | |
if (process.waitFor() == 0) isConnected = true; | |
else isConnected = false; | |
This approach works synchronously so that you just wait for the response to tell whether you have a connection or not and it takes no time. However, in some mobile devices for specific brands, the framework does not allow performing this process in Runtime, so you can not eventually rely on it. | |
Instead, we can make a normal HTTP connection request to the server. | |
Start by creating a method called checkInternetConnection which checks first if wifi or mobile data are connected to any network by using the above method. Then it starts establishing an HTTP URL connection: | |
public synchronized void checkInternetConnection(ConnectivityCallback callback) { | |
appExecutors.getNetworkIO().execute(() -> { | |
if (isNetworkAvailable()) { | |
HttpURLConnection connection = null; | |
try { | |
connection = (HttpURLConnection) | |
new URL("http://clients3.google.co/generate_204") | |
.openConnection(); | |
connection | |
.setRequestProperty("User-Agent", "Android"); | |
connection | |
.setRequestProperty("Connection", "close"); | |
connection.setConnectTimeout(1000); | |
connection.connect(); | |
boolean isConnected = | |
connection.getResponseCode() == 204 | |
&& connection.getContentLength() == 0; | |
postCallback(callback, isConnected); | |
connection.disconnect(); | |
} catch (Exception e) { | |
postCallback(callback, false); | |
if(connection != null) connection.disconnect(); | |
} | |
} else { | |
postCallback(callback, false); | |
} | |
}); | |
} | |
ConnectivityCallback is an inner interface having an abstract function which we’ll use to communicate with our UI classes when the server’s response comes back. | |
public interface ConnectivityCallback { | |
void onDetected(boolean isConnected); | |
} | |
In the above checkInternetConnection function we used: “http://clients3.google.com/generate_204” instead of Google’s normal URL “http://www.google.com” since the first is a bit more efficient so that we don’t have to grab the whole web page. | |
For a successful request, the response code must be equals to 204 and no content is returned back. | |
We used “setRequestProperty()” to set headers for the request for the server. Also, we specified the connection timeout to be one second which is a reasonable time. | |
But wait! Android framework does not allow network operations on the main thread so we need to use the above code on another thread. Consequently, we’ll have to post the result on the main thread again. You can use whatever is convenience for you to perform both of these operations. I would use a singleton AppExecutors class which provides executor threads for both of our cases. | |
postCallback() is a helper method that posts our result to the interface on the main thread. | |
private void postCallback(ConnectivityCallback callBack, boolean isConnected) { | |
appExecutors.mainThread().execute(() -> | |
callBack.onDetected(isConnected)); | |
} | |
That’s it! | |
To check internet connectivity in an activity: | |
@AndroidEntryPoint | |
public class MainActivity extends AppCompatActivity { | |
@Inject | |
NetworkConnectivity networkConnectivity; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
} | |
public void internetCheckBtnClicked(View view) { | |
networkConnectivity.checkInternetConnection((isConnected) -> | |
Toast | |
.makeText(this, isConnected + "", Toast.LENGTH_SHORT) | |
.show() | |
); | |
} | |
} | |
Notice that I used Hilt for Dependency Injection, you can use manual DI: Networkconnectivity networkConnectivity = | |
new NetworkConnectivity.ConnectivityCallback() { | |
public void onDetected(boolean isConnected) { | |
} | |
} | |
In newer devices, Android may produce a security exception due to using HTTP URL connection. To fix this, add android:usesCleartextTraffic=”true” in your app manifest within application tag or use HTTPS instead of HTTP connections. So, pay attention to exception handling in your checkInternetConnection method |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment