-
-
Save iRYO400/5da269f4d5edbc365c952bdcbdfe6b68 to your computer and use it in GitHub Desktop.
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) | |
} | |
} | |
} | |
} | |
} |
Great! Thanks for this...
Can you please provide java code for the same ?
@igoswamirohit nope, I won't, you better try it yourself :)
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
@agvozditskiy Network might have an internet connection, but the device is not connected to the network anymore.
@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?
@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()
@GokhanArik we use the same solution )
private fun setListeners() {
ConnectivityMonitor(this, this) { isConnected ->
//TODO whatever you need
}
}
getting isConnected true even I disabled cellular network,
@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
@iRYO400 Thanks for the code
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)
}
}
}
}
}
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
Example of usage in Activity
In Fragment