I will give you information about how to use Connectivity manager to listen network changes.
In Android development, managing network connectivity is crucial for ensuring your app behaves correctly when switching between networks or losing connection. One of the best ways to handle network changes is by using the ConnectivityManager. This class provides an easy way to monitor and react to changes in network status in real time. In this article, we’ll explore how to use NetworkCallback
to detect network availability, handle network capabilities, such as internet access and observe network status in real time using Flow.
What is ConnectivityManager?
ConnectivityManager
is a system service in Android that provides access to information about the network connectivity status of the device. It allows developers to monitor network connectivity and manage network-related operations like detecting if a network is available, if the device has internet access, and switching between different types of networks (e.g., Wi-Fi, mobile data).
With ConnectivityManager
, you can:
- Check the status of the network (whether it’s connected or not).
- Monitor network types (Wi-Fi, cellular, Ethernet, etc.).
- Register listeners (callbacks) to react to network changes.
- Determine if the network connection is suitable for certain operations (e.g., whether it has internet access or is valid).
ConnectivityManager
is commonly used when apps need to handle network connectivity changes or need to adapt their behaviour depending on the current network status.
We will create network observer in few steps.
private var connectivityManager: ConnectivityManager? =
context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
We will use NetworkCallback of ConnectivityManager to observe connectivity changes using different callback methods.
What is NetworkCallback
?
NetworkCallback
is a class in the Android ConnectivityManager
API that provides an easy way to monitor changes in network connectivity. By registering a NetworkCallback
, you can listen for changes such as when a network becomes available, is lost, or has its capabilities changed (e.g., it gains internet access or loses validation).
Using NetworkCallback
, your app can respond dynamically to network status changes and adapt accordingly, providing a seamless experience for users who may frequently switch networks, lose connection, or have limited connectivity.
There are several methods to observe network events.
Key Network Callback Methods:
NetworkCallback
provides several methods to handle different network events:
onAvailable(Network network)
: Called when a network becomes available.onLost(Network network)
: Called when a network is lost (e.g., the user switches to a different network).onUnavailable()
: Called when no network is available.onCapabilitiesChanged(Network network, NetworkCapabilities capabilities)
: Called when the capabilities of a network change (e.g., the network gains or loses internet access or validation).
val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
connectivityManager?.getNetworkCapabilities(network)?.let {
if (it.hasCapability(NET_CAPABILITY_INTERNET)) {
// trySend(true)
}
}
}override fun onLost(network: Network) {
// trySend(false)
}
override fun onUnavailable() {
// trySend(false)
}
override fun onCapabilitiesChanged(
network: Network,
capabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, capabilities)
if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
// trySend(true)
} else {
// trySend(false)
}
}
}
We will now create network request using NetworkRequest
Builder. This NetworkRequest
is designed to request a network that meets certain capabilities and transport types, specifically focusing on networks that can provide internet access and support multiple types of network transport (Wi-Fi, Ethernet, and cellular).
val networkRequest = NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build()
- NetworkRequest.Builder():
This creates an instance of NetworkRequest.Builder
, which is used to specify the criteria for the type of network you want to request. You can add capabilities and transport types to the builder before finally building the NetworkRequest
using the build()
method.
- addCapability(NET_CAPABILITY_INTERNET):
This adds a capability requirement for the network. In this case, NET_CAPABILITY_INTERNET
means that the network must provide internet access. This ensures that the NetworkRequest
will only match networks that are capable of providing internet connectivity (e.g., Wi-Fi, cellular, Ethernet with internet access).
This adds a transport type requirement for the network. The transport type refers to the medium or technology used for the network connection. By adding TRANSPORT_WIFI
, TRANSPORT_ETHERNET
, TRANSPORT_CELLULAR
you’re telling the NetworkRequest
that you are interested in Wi-Fi, Ethernet or Cellular networks. This would match networks using Wi-Fi, Ethernet, Cellular as the underlying technology.
To register network callback, we need to pass two params. First, which is networkRequest and another is networkCallback.
connectivityManager?.registerNetworkCallback(networkRequest, networkCallback)
Yeah! Our network observer is ready to use. but wait we have to add flow to send realtime network event changes.
So, we will use Flow API to send realtime changes. We use trySend method to send network event changes.
trySend()
:
The trySend()
method is a Kotlin function commonly used in Coroutines to send values to a Channel
or SharedFlow
in a non-blocking manner. It is a suspending function used in conjunction with Kotlin Coroutines to emit values to a Channel
or a SharedFlow
without blocking the calling thread. If the value cannot be sent at that moment (for example, if the Channel
is full or the flow is not ready to accept new values), it will return a Boolean
indicating whether the value was successfully sent.
- Non-blocking: Unlike the
send()
method,trySend()
is non-blocking. If the operation cannot proceed immediately, it will returnfalse
instead of suspending the caller. - Return Value: It returns a
ChannelResult
(orBoolean
in some versions of Kotlin) which is: true
: The value was successfully sent.false
: The value could not be sent at that moment.
We will send true when network is available else will send false.
val isConnectedFlow: Flow<Boolean>
get() = callbackFlow {
val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
connectivityManager?.getNetworkCapabilities(network)?.let {
if (it.hasCapability(NET_CAPABILITY_INTERNET)) {
trySend(true)
}
}
}override fun onLost(network: Network) {
trySend(false)
}
override fun onUnavailable() {
trySend(false)
}
override fun onCapabilitiesChanged(
network: Network,
capabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, capabilities)
if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
trySend(true)
} else {
trySend(false)
}
}
}
val networkRequest = NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build()
connectivityManager?.registerNetworkCallback(networkRequest, networkCallback)
awaitClose {
connectivityManager?.unregisterNetworkCallback(networkCallback)
}
}
How to use now?
Create viewmodel
class MainViewModel(networkObserver: NetworkObserver): ViewModel() {val isConnected = networkObserver.isConnectedFlow.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000L),
initialValue = false
)
}
Observe isConnected
in your view or compose.
val viewModel = viewModel<MainViewModel> {
MainViewModel(NetworkObserver(this@MainActivity))
}
val isConnected by viewModel.isConnected.collectAsState()print("NetworkStatus: $isConnected") // isConnected is true = connected, false = not connected
Without or with ViewModel you can use it inside fragment or activity by initialise NetworkObserver class and pass context argument.
val networkObserver = NetworkObserver(context)// Add below code in your onCreate() method of Activity or onViewCreated() method of fragment
viewLifecycleOwner.lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED){
networkObserver.isConnected.collectLatest {
print("NetworkStatus: $isConnected")
}
}
}
It’s Done.
Second way using lifecycleObserver. You can checkout this project.
Sample project: