I want to get Network State means whether the Connected network has internet connection in Jetpack Compose. How to achieve it
If your running into trouble with the connectivityManager.activeNetworkInfo being deprecated, try using this:
private fun isInternetAvailable(context: Context): Boolean {
var result = false
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkCapabilities = connectivityManager.activeNetwork ?: return false
val actNw = connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
result = when {
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} else {
connectivityManager.run {
connectivityManager.activeNetworkInfo?.run {
result = when (type) {
ConnectivityManager.TYPE_WIFI -> true
ConnectivityManager.TYPE_MOBILE -> true
ConnectivityManager.TYPE_ETHERNET -> true
else -> false
}
}
}
}
return result
}
I got the answer from the accepted answer of another question. Feel free to check it out: activeNetworkInfo is Deprecated
When working with JC, use this to access the context:
val context = LocalContext.current
I'm sharing my connectivity flow solution here, even though an answer has been accepted. This solution seamlessly integrates with Jetpack Compose and has been thoroughly debugged and simplified. Feel free to try and copy-paste the solution.
It combines the solution used by Google in WorkManager and callbackFlow.
Here are the relevant classes: NetworkState, which holds the current network states, and ConnectionState, which is important for UI components.
private data class NetworkState(
/** Determines if the network is connected. */
val isConnected: Boolean,
/** Determines if the network is validated - has a working Internet connection. */
val isValidated: Boolean,
/** Determines if the network is metered. */
val isMetered: Boolean,
/** Determines if the network is not roaming. */
val isNotRoaming: Boolean
)
sealed class ConnectionState {
object Available : ConnectionState()
object Unavailable : ConnectionState()
}
To compute the NetworkState, use the activeNetworkState property extension on ConnectivityManager.
@Suppress("DEPRECATION")
private val ConnectivityManager.activeNetworkState: NetworkState
@SuppressLint("MissingPermission")
get() {
// Use getActiveNetworkInfo() instead of getNetworkInfo(network) because it can detect VPNs.
val info = activeNetworkInfo
val isConnected = info != null && info.isConnected
val isValidated = isActiveNetworkValidated
val isMetered = ConnectivityManagerCompat.isActiveNetworkMetered(this)
val isNotRoaming = info != null && !info.isRoaming
return NetworkState(isConnected, isValidated, isMetered, isNotRoaming)
}
For checking if the active network is validated, use the isActiveNetworkValidated property extension on ConnectivityManager.
private val ConnectivityManager.isActiveNetworkValidated: Boolean
@SuppressLint("RestrictedApi", "MissingPermission")
get() =
if (Build.VERSION.SDK_INT < 23) {
false // NET_CAPABILITY_VALIDATED not available until API 23. Used on API 26+.
} else
try {
val network = activeNetwork
val capabilities = getNetworkCapabilities(network)
(capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) ?: false
} catch (exception: SecurityException) {
Timber.tag("NetworkStateTracker").e(exception, "Unable to validate active network")
false
}
A callbackFlow to convert a NetworkCallback to a Flow. Everytime there is a callback method called, this function computes the ConnectivityState and sends it.
/** Network Utility to observe Internet connectivity status */
@SuppressLint("MissingPermission")
@ExperimentalCoroutinesApi
private fun Context.observeConnectivityAsFlow() =
callbackFlow {
val connectivityManager =
getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
fun sendConnectionState() =
with(connectivityManager.activeNetworkState) {
if (Build.VERSION.SDK_INT < 23) {
if (isConnected) {
trySend(ConnectionState.Available)
} else {
trySend(ConnectionState.Unavailable)
}
} else {
if (isConnected && isValidated) {
trySend(ConnectionState.Available)
} else {
trySend(ConnectionState.Unavailable)
}
}
}
val networkRequest =
NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build()
val networkCallback =
object : ConnectivityManager.NetworkCallback() {
// satisfies network capability and transport requirements requested in networkRequest
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
sendConnectionState()
}
override fun onLost(network: Network) {
sendConnectionState()
}
}
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
awaitClose {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
}
.distinctUntilChanged()
.flowOn(Dispatchers.IO)
A publicly available method to collect the ConnectionState
@ExperimentalCoroutinesApi
@Composable
fun connectivityState(): State<ConnectionState> {
val context = LocalContext.current
return produceState<ConnectionState>(initialValue = ConnectionState.Unavailable) {
context.observeConnectivityAsFlow().collect { value = it }
}
}
And finally in your composable
@Composable
fun YourAwesomeComposable(
modifier: Modifier = Modifier,
) {
val networkConnectivity by connectivityState()
...
...
if (networkConnectivity == ConnectionState.Unavailable) {
// Unavailable UI
} else {
// Available UI
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With