Android & Kotlin

Android check internet connection

Pinterest LinkedIn Tumblr

In this blog, I’ll show how to check internet connection in android programmatically. While we are developing a professional app, you may need to check internet available or not. For example, while you are calling APIs you may need to check internet connection several times in an app. In this example, we’ll learn how we can check internet connections any place and anywhere.

I’m going to create a demo application, This app will automatically detect the internet changes using an internet connection listener. For the demonstration, I’ll create a sample app that app will capable of continuously check internet connection with android. So let started.

Create Android Project

Let move to Android Studio, and create a fresh project with some default template. We are going to use java 1.8 stuff in our project so lets set java version in app build.gradle file

  compileOptions {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }
    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8.toString()
    }  

Add ACCESS_NETWORK_STATE permission in Manifest

For detecting network permission we required some permission so let open the AndroidManifest and add below permission.

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

Write a ConnectivityProvider interface

I’m going to write complete solution for check internet connection for pre and post LOLLIPOP devices solution in a single interface. Please have a look

package com.detectnetworkchange.connectivity.base

import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkInfo
import android.os.Build
import androidx.annotation.RequiresApi
import com.detectnetworkchange.connectivity.ConnectivityProviderImpl
import com.detectnetworkchange.connectivity.ConnectivityProviderLegacyImpl

interface ConnectivityProvider {

    fun subscribe()

    fun getNetworkState(): NetworkState

    @Suppress("MemberVisibilityCanBePrivate", "CanBeParameter")
    sealed class NetworkState {
        object NotConnectedState : NetworkState()

        sealed class ConnectedState(val hasInternet: Boolean) : NetworkState() {

            @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
            data class Connected(val capabilities: NetworkCapabilities) : ConnectedState(
                    capabilities.hasCapability(NET_CAPABILITY_INTERNET)
            )

            @Suppress("DEPRECATION")
            data class ConnectedLegacy(val networkInfo: NetworkInfo) : ConnectedState(
                    networkInfo.isConnectedOrConnecting
            )
        }
    }

    companion object {
        @JvmStatic
        fun createProvider(context: Context): ConnectivityProvider {
            val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                ConnectivityProviderImpl(cm)
            } else {
                ConnectivityProviderLegacyImpl(context, cm)
            }
        }
    }
}

Extend ConnectivityProvider interface

Now create a abstract class named ConnectivityProviderBaseImpl which extends ConnectivityProvider interface, like below

package com.detectnetworkchange.connectivity.base

import com.detectnetworkchange.CONNECTED
import com.detectnetworkchange.DISCONNECTED
import com.detectnetworkchange.NetWorkManger
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState

abstract class ConnectivityProviderBaseImpl : ConnectivityProvider {
    override fun subscribe() {
        subscribeListener()
        //init status
        dispatchChange(getNetworkState())
    }

    protected fun dispatchChange(state: NetworkState) {
        val networkState = if (state.hasInternet()) CONNECTED else DISCONNECTED
        if (networkState != NetWorkManger.networkStatus.value) {
            NetWorkManger.networkStatus.postValue(networkState)
        }
    }

    private fun NetworkState.hasInternet(): Boolean {
        return (this as? NetworkState.ConnectedState)?.hasInternet == true
    }

    protected abstract fun subscribeListener()
}

Write a actual implementation of ConnectivityProvider

package com.detectnetworkchange.connectivity

import android.net.ConnectivityManager
import android.net.ConnectivityManager.NetworkCallback
import android.net.Network
import android.net.NetworkCapabilities
import android.os.Build
import androidx.annotation.RequiresApi
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState.ConnectedState.Connected
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState.NotConnectedState
import com.detectnetworkchange.connectivity.base.ConnectivityProviderBaseImpl

@RequiresApi(Build.VERSION_CODES.N)
class ConnectivityProviderImpl(private val cm: ConnectivityManager) :
        ConnectivityProviderBaseImpl() {

    private val networkCallback = ConnectivityCallback()

    override fun subscribeListener() {
        cm.registerDefaultNetworkCallback(networkCallback)
    }

    override fun getNetworkState(): NetworkState {
        val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
        return if (capabilities != null) {
            Connected(capabilities)
        } else {
            NotConnectedState
        }
    }

    private inner class ConnectivityCallback : NetworkCallback() {

        override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) {
            dispatchChange(Connected(capabilities))
        }

        override fun onLost(network: Network) {
            dispatchChange(NotConnectedState)
        }
    }
}
package com.detectnetworkchange.connectivity

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.ConnectivityManager.CONNECTIVITY_ACTION
import android.net.ConnectivityManager.EXTRA_NETWORK_INFO
import android.net.NetworkInfo
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState.ConnectedState.ConnectedLegacy
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState.NotConnectedState
import com.detectnetworkchange.connectivity.base.ConnectivityProviderBaseImpl

@Suppress("DEPRECATION")
class ConnectivityProviderLegacyImpl(
        private val context: Context,
        private val cm: ConnectivityManager
) : ConnectivityProviderBaseImpl() {

    private val receiver = ConnectivityReceiver()

    override fun subscribeListener() {
        context.registerReceiver(receiver, IntentFilter(CONNECTIVITY_ACTION))
    }

    override fun getNetworkState(): NetworkState {
        val activeNetworkInfo = cm.activeNetworkInfo
        return if (activeNetworkInfo != null) {
            ConnectedLegacy(activeNetworkInfo)
        } else {
            NotConnectedState
        }
    }

    private inner class ConnectivityReceiver : BroadcastReceiver() {
        override fun onReceive(c: Context, intent: Intent) {
            // on some devices ConnectivityManager.getActiveNetworkInfo() does not provide the correct network state
            val networkInfo = cm.activeNetworkInfo
            val fallbackNetworkInfo: NetworkInfo? = intent.getParcelableExtra(EXTRA_NETWORK_INFO)
            // a set of dirty workarounds
            val state: NetworkState =
                    if (networkInfo?.isConnectedOrConnecting == true) {
                        ConnectedLegacy(networkInfo)
                    } else if (networkInfo != null && fallbackNetworkInfo != null &&
                            networkInfo.isConnectedOrConnecting != fallbackNetworkInfo.isConnectedOrConnecting
                    ) {
                        ConnectedLegacy(fallbackNetworkInfo)
                    } else {
                        val state = networkInfo ?: fallbackNetworkInfo
                        if (state != null) ConnectedLegacy(state) else NotConnectedState
                    }
            dispatchChange(state)
        }
    }
}

Let’s create a NetWorkManger class

In this class we have one live data object which hold the internet state, It can be accessible threw out the application.

package com.detectnetworkchange

import androidx.lifecycle.MutableLiveData


const val DISCONNECTED = 0
const val CONNECTED = 1

object NetWorkManger {
    val networkStatus = MutableLiveData<Int>()

    fun isDisconnected(): Boolean {
        return networkStatus.value == DISCONNECTED
    }
}

class NetWorkDisconnectedException : Throwable()

Finally subscribe the ConnectivityProvider instance in application class

package com.detectnetworkchange

import android.app.ActivityManager
import android.app.Application
import android.content.Context
import android.os.Build
import android.os.Process
import com.detectnetworkchange.connectivity.base.ConnectivityProvider

class DetectNetworkChangeDemoApp : Application() {
    override fun onCreate() {
        super.onCreate()
        if (isMainProcess()) {
            ConnectivityProvider.createProvider(this).subscribe()
        }
    }

    // your package name is the same with your main process name
    private fun isMainProcess(): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            packageName == getProcessName()
        } else packageName == getProcessNameLegacy()
    }

    // you can use this method to get current process name, you will get
    private fun getProcessNameLegacy(): String? {
        val mypid = Process.myPid()
        val manager =
            getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val infos = manager.runningAppProcesses
        for (info in infos) {
            if (info.pid == mypid) {
                return info.processName
            }
        }
        // may never return null
        return null
    }
}

This way you can observe network changes

package com.detectnetworkchange

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Suppose you want to check network status before calling APIs then use this way
        Log.d("MainActivity","Network connected "+!NetWorkManger.isDisconnected())
        // if you want observe network status then use this way
        NetWorkManger.networkStatus.observe(this, Observer {
            when (it) {
                CONNECTED -> status.text ="Internet is connected"
                DISCONNECTED -> status.text ="Internet disconnected"
            }
        })


    }
}

Download Solution Code

Write A Comment