NetworkMonitor: new strategy, looks like it works.

This commit is contained in:
ganfra 2023-06-27 17:58:45 +02:00
parent f6a1db44a6
commit 98c146c633

View file

@ -38,8 +38,10 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.atomic.AtomicInteger
import javax.inject.Inject import javax.inject.Inject
@ContributesBinding(scope = AppScope::class) @ContributesBinding(scope = AppScope::class)
@ -54,27 +56,31 @@ class NetworkMonitorImpl @Inject constructor(
override val connectivity: StateFlow<NetworkStatus> = callbackFlow { override val connectivity: StateFlow<NetworkStatus> = callbackFlow {
/** /**
* Assume there is no network available as soon as onLost is called. * Calling connectivityManager methods synchronously from the callbacks is not safe.
* Reading activeNetwork synchronously from the callback is not safe. * So instead we just keep the count of active networks, ie. those checking the capability request.
* If there is an other active network we'll get some callback in onCapabilitiesChanged.
* Debounce the result to avoid quick offline<->online changes. * Debounce the result to avoid quick offline<->online changes.
*/ */
val callback = object : ConnectivityManager.NetworkCallback() { val callback = object : ConnectivityManager.NetworkCallback() {
private val activeNetworksCount = AtomicInteger(0)
override fun onLost(network: Network) { override fun onLost(network: Network) {
trySendBlocking(NetworkStatus.Offline) if (activeNetworksCount.decrementAndGet() == 0) {
trySendBlocking(NetworkStatus.Offline)
}
} }
override fun onCapabilitiesChanged( override fun onAvailable(network: Network) {
network: Network, if (activeNetworksCount.incrementAndGet() > 0) {
networkCapabilities: NetworkCapabilities trySendBlocking(NetworkStatus.Online)
) { }
trySendBlocking(networkCapabilities.getNetworkStatus())
} }
} }
trySendBlocking(connectivityManager.activeNetworkStatus()) trySendBlocking(connectivityManager.activeNetworkStatus())
val request = NetworkRequest.Builder() val request = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
.build() .build()
connectivityManager.registerNetworkCallback(request, callback) connectivityManager.registerNetworkCallback(request, callback)
Timber.d("Subscribe") Timber.d("Subscribe")
awaitClose { awaitClose {
@ -84,6 +90,9 @@ class NetworkMonitorImpl @Inject constructor(
} }
.distinctUntilChanged() .distinctUntilChanged()
.debounce(300) .debounce(300)
.onEach {
Timber.d("NetworkStatus changed=$it")
}
.stateIn(appCoroutineScope, SharingStarted.WhileSubscribed(), connectivityManager.activeNetworkStatus()) .stateIn(appCoroutineScope, SharingStarted.WhileSubscribed(), connectivityManager.activeNetworkStatus())
private fun ConnectivityManager.activeNetworkStatus(): NetworkStatus { private fun ConnectivityManager.activeNetworkStatus(): NetworkStatus {