Skip to content

Instantly share code, notes, and snippets.

@iRYO400
Created April 30, 2020 09:41
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save iRYO400/5da269f4d5edbc365c952bdcbdfe6b68 to your computer and use it in GitHub Desktop.
Save iRYO400/5da269f4d5edbc365c952bdcbdfe6b68 to your computer and use it in GitHub Desktop.
Check Internet Connection [API21+][API29+ supported] Lifecycle aware
import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import timber.log.Timber
class ConnectivityMonitor(
context: Context,
lifecycleOwner: LifecycleOwner,
private val callback: (Boolean) -> Unit
) : LifecycleObserver {
private var connectivityManager =
context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
private val networkRequest = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.build()
init {
lifecycleOwner.lifecycle.addObserver(this)
}
@Suppress("unused")
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onResume() {
toggleConnectionState(connectivityManager.isDefaultNetworkActive)
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
}
@Suppress("unused")
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onPause() {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
private fun toggleConnectionState(isConnected: Boolean) = callback.invoke(isConnected)
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, networkCapabilities)
Timber.d("onCapabilitiesChanged")
lastInternetConnectionCheck()
}
override fun onAvailable(network: Network) {
super.onAvailable(network)
Timber.d("onAvailable")
lastInternetConnectionCheck()
}
override fun onLost(network: Network) {
super.onLost(network)
Timber.d("onLost")
lastInternetConnectionCheck()
}
private fun lastInternetConnectionCheck() =
connectivityManager.allNetworks.forEach { network ->
network?.let {
connectivityManager.getNetworkCapabilities(it)
?.let { networkCapabilities ->
val netInternet =
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
val transportCellular =
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
val transportWifi =
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
val transportEthernet =
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
val transportVpn =
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
val isConnected = netInternet ||
transportWifi || transportCellular ||
transportEthernet || transportVpn
Timber.d("Connections State $isConnected netInternet: $netInternet, WiFi: $transportWifi, Cellular: $transportCellular, Ethernet: $transportEthernet, VPN: $transportVpn")
toggleConnectionState(isConnected)
}
}
}
}
}
@iRYO400
Copy link
Author

iRYO400 commented Apr 30, 2020

Example of usage in Activity

    private fun setListeners() {
        ConnectivityMonitor(this, this) { isConnected ->
            //TODO whatever you need
        }
    }

In Fragment

    private fun setListeners() {
        ConnectivityMonitor(requireContext(), viewLifecycleOwner) { isConnected ->
            //TODO whatever you need
        }
    }

@PasanBhanu
Copy link

Great! Thanks for this...

@igoswamirohit
Copy link

Can you please provide java code for the same ?

@iRYO400
Copy link
Author

iRYO400 commented May 27, 2020

@igoswamirohit nope, I won't, you better try it yourself :)

@agvozditskiy
Copy link

agvozditskiy commented May 28, 2020

Hi. Try to turn off all except cellular. And then turn off mobile data. onLost callback is triggered, but the network has internet.

override fun onLost(network: Network) {
                    super.onLost(network)
                    Timber.d("onLost")
                    val hasNet = connectivityManager
                        .getNetworkCapabilities(network)
                        ?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                    Timber.d("network $network, hasNet=$hasNet")

                    lastInternetConnectionCheck(network)
                    checkOld()
                }
@Suppress("DEPRECATION")
    private fun checkOld() {
        val hasConnection = connectivityManager.activeNetworkInfo?.isConnectedOrConnecting == true
        Timber.d("Old check = $hasConnection")
    }

Output:

D/AndroidNetworkStateManager: onLost
D/AndroidNetworkStateManager: network 126, hasnet=true
D/AndroidNetworkStateManager: netInternet: true, WiFi: false, Cellular: true, Ethernet: false, VPN: false
D/AndroidNetworkStateManager: Connections State true
D/AndroidNetworkStateManager: Old check = false

@GokhanArik
Copy link

@agvozditskiy Network might have an internet connection, but the device is not connected to the network anymore.

@agvozditskiy
Copy link

agvozditskiy commented Jul 13, 2020

@agvozditskiy Network might have an internet connection, but the device is not connected to the network anymore.

@GokhanArik And how to track this state correct?

@GokhanArik
Copy link

@agvozditskiy Check this gist, we discussed this there in detail: https://gist.github.com/PasanBhanu/730a32a9eeb180ec2950c172d54bb06a#gistcomment-3374351

I ended up using the new callback, and inside callback using deprecated methods to check -isConnectedOrconnecting()

@agvozditskiy
Copy link

@GokhanArik we use the same solution )

@krb449
Copy link

krb449 commented Aug 6, 2020

private fun setListeners() {
ConnectivityMonitor(this, this) { isConnected ->
//TODO whatever you need
}
}

getting isConnected true even I disabled cellular network,

@jidekrm
Copy link

jidekrm commented Dec 23, 2020

@krb449 That behavior is coming from lastInternetConnectionCheck(). As long as any of the variables transportCellular, ... is true, netInternet will be true and toggleConnectionState/isConnected will be true. I think that also explains @agvozditskiy observation.
For my project, I just included only netInternet in isConnected and so far I have a consistent behavior.
val isConnected = netInternet
// ||transportWifi || transportCellular || transportEthernet || transportVpn

@jidekrm
Copy link

jidekrm commented Dec 23, 2020

@iRYO400 Thanks for the code

@aornano
Copy link

aornano commented Apr 11, 2021

Hello guys, allNetworks array become empty (zero size) when the connection is lost and the callback is not triggered, so the last function should be:

private fun lastInternetConnectionCheck() {
            if (connectivityManager.allNetworks.size == 0) {
                toggleConnectionState(false)
            } else {
                connectivityManager.allNetworks.forEach { network ->
                    network?.let {
                        connectivityManager.getNetworkCapabilities(it)
                                ?.let { networkCapabilities ->
                                    val netInternet =
                                            networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                                    val transportCellular =
                                            networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
                                    val transportWifi =
                                            networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
                                    val transportEthernet =
                                            networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
                                    val transportVpn =
                                            networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)

                                    val isConnected = netInternet ||
                                    transportWifi || transportCellular ||
                                    transportEthernet || transportVpn

                                    Log.d("DEBUG", "Connections State $isConnected netInternet: $netInternet, WiFi: $transportWifi, Cellular: $transportCellular, Ethernet: $transportEthernet, VPN: $transportVpn")
                                    toggleConnectionState(isConnected)
                                }
                    }
                }
            }
        }

@anilkt87
Copy link

Seems this code is not working i have tried it but internet is not there then also private fun setListeners() {
ConnectivityMonitor(this, this) { isConnected ->
//TODO whatever you need
}
}
isConnected coming true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment