Android: Intercept on no internet connection

Elye
Elye
Jul 18 · 3 min read

I have blog compare iOS and Android networking previously. iOS with Alamofire library automatically provide capability to detect when data connection is not on. However Android OkHttp library does provide that by default.

So in this blog, I’ll show how to setup no internet connection detection naturally in OkHttp, which only needs to be done once in your code, and used by all network call.

I’ll show you how it is done in a reverse order.

Setup the interceptor in the OkHttpClient

As show in my previous blog, in Android, we’ll need to have OkHttpClient for our network call.

OkHttp provide us a way to intercept the network call through it’s interceptor plugin into the OkHttpClient. We’ll just need to create our interceptor for any specific function we want to do, in this case, which is `check for no network`

To make OkHttpClient no network aware, we’ll provide it with a NoConnectionInterceptor object.

OkHttpClient.Builder()
.addInterceptor(NoConnectionInterceptor(context))
.build()

Note: In the example code, I use Dagger 2 to inject the OkHttpClient to make the entire application more structured and decoupled. If you like to learn about Dagger 2, check out this blog.

Custom made NoConnectionInterceptor

Let’s create our custom No Connection Interceptor.

Detect that WIFI/CELLULAR connection is OFF

To do that, first of all, we’ll need to have the permission set in AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Then write the needing code to check for no network.

Firstly, get the connectionManager from the context, as it will provide object with information of the network availability

val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

Before Android Marshmallow, we’ll have to to get the data from activeNetworkInfo in the connectivityManager

private fun preAndroidMInternetCheck(
connectivityManager: ConnectivityManager): Boolean {
val activeNetwork = connectivityManager.activeNetworkInfo
if (activeNetwork != null) {
return (activeNetwork.type == ConnectivityManager.TYPE_WIFI ||
activeNetwork.type == ConnectivityManager.TYPE_MOBILE)
}
return false
}

But in Android Marshmallow and newer, we’ll have to get from activeNetwork of connectivityManager instead.

private fun postAndroidMInternetCheck(
connectivityManager: ConnectivityManager): Boolean {
val network = connectivityManager.activeNetwork
val connection =
connectivityManager.getNetworkCapabilities(network)

return connection != null && (
connection.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
connection.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
}

Then combine them together as below.

private fun isConnectionOn(): Boolean {
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as
ConnectivityManager

return if (android.os.Build.VERSION.SDK_INT >=
android.os.Build.VERSION_CODES.M) {
postAndroidMInternetCheck(connectivityManager)
} else {
preAndroidMInternetCheck(connectivityManager)
}
}

Refer to the git repo for the full code.

Detect that INTERNET is available

The above just state that is the WiFi or Cellular Data is ON. But that doesn’t guarantee if there’s internet.

This check is optional, as we perform a network call, it will timeout and return appropriate error too if no internet.

However for speedy response of no internet, one could perform a quick special connection to Google Public DNS (i.e. 8.8.8.8) to check.

The code as below.

private fun isInternetAvailable(): Boolean {
return try {
val timeoutMs = 1500
val sock = Socket()
val sockaddr = InetSocketAddress("8.8.8.8", 53)

sock.connect(sockaddr, timeoutMs)
sock.close()

true
} catch (e: IOException) {
false
}
}

Credit to the Stackoverflow solution provided below.

Combine two checks together in the Interceptor

Now, create the NoConnectionInterceptor, which implemented from Interceptor interface.

class NoConnectionInterceptor(
private val context: Context) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
return if (!isConnectionOn()) {
throw NoConnectivityException()
} else if(!isInternetAvailable()) {
throw NoInternetException()
} else {
chain.proceed(chain.request())
}
}
// ... Other Codes ...}

To make the no connection error more meaningful, I have already create 2 custom exceptions as below

class NoConnectivityException : IOException() {
override val message: String
get() =
"No network available, please check your WiFi or Data connection"
}

class NoInternetException() : IOException() {
override val message: String
get() =
"No internet available, please check your connected WIFi or Data"
}

TL;DR

With this in place, now your OkHttpClient is no connection aware, and you could use it to perform network call. If no network is detected, it will automatically throw the exception to notify you.

You could get the code from


I hope this post is helpful to you. You could check out my other interesting topics here.

Follow me on medium, Twitter, Facebook or Reddit for little tips and learning on Android, Kotlin etc related topics. ~Elye~

Elye

Written by

Elye

Learning and Sharing Android and iOS Development

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade