Offload connectivity monitor to a background thread

Change-Id: I9a2ef7766ae6abc6d8a7c86a4b49ef3c795e446c
pull/1368/head
Tomáš Mlynarič 9 months ago
parent 88c3eb0b90
commit 6b35cbb328

@ -26,57 +26,71 @@ import android.net.NetworkRequest.Builder
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.Build.VERSION_CODES import android.os.Build.VERSION_CODES
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.tracing.Trace
import androidx.tracing.trace
import com.google.samples.apps.nowinandroid.core.network.Dispatcher
import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.IO
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flowOn
import javax.inject.Inject import javax.inject.Inject
internal class ConnectivityManagerNetworkMonitor @Inject constructor( internal class ConnectivityManagerNetworkMonitor @Inject constructor(
@ApplicationContext private val context: Context, @ApplicationContext private val context: Context,
@Dispatcher(IO) private val ioDispatcher: CoroutineDispatcher,
) : NetworkMonitor { ) : NetworkMonitor {
override val isOnline: Flow<Boolean> = callbackFlow { override val isOnline: Flow<Boolean> = callbackFlow {
val connectivityManager = context.getSystemService<ConnectivityManager>() trace("NetworkMonitor.callbackFlow") {
if (connectivityManager == null) { val connectivityManager = context.getSystemService<ConnectivityManager>()
channel.trySend(false) if (connectivityManager == null) {
channel.close() channel.trySend(false)
return@callbackFlow channel.close()
} return@callbackFlow
}
/**
* The callback's methods are invoked on changes to *any* network matching the [NetworkRequest],
* not just the active network. So we can simply track the presence (or absence) of such [Network].
*/
val callback = object : NetworkCallback() {
/** private val networks = mutableSetOf<Network>()
* The callback's methods are invoked on changes to *any* network matching the [NetworkRequest],
* not just the active network. So we can simply track the presence (or absence) of such [Network].
*/
val callback = object : NetworkCallback() {
private val networks = mutableSetOf<Network>() override fun onAvailable(network: Network) {
networks += network
channel.trySend(true)
}
override fun onAvailable(network: Network) { override fun onLost(network: Network) {
networks += network networks -= network
channel.trySend(true) channel.trySend(networks.isNotEmpty())
}
} }
override fun onLost(network: Network) { trace("NetworkMonitor.registerNetworkCallback") {
networks -= network val request = Builder()
channel.trySend(networks.isNotEmpty()) .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
connectivityManager.registerNetworkCallback(request, callback)
} }
}
val request = Builder() /**
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) * Sends the latest connectivity status to the underlying channel.
.build() */
connectivityManager.registerNetworkCallback(request, callback) channel.trySend(connectivityManager.isCurrentlyConnected())
/** Trace.endSection()
* Sends the latest connectivity status to the underlying channel.
*/
channel.trySend(connectivityManager.isCurrentlyConnected())
awaitClose { awaitClose {
connectivityManager.unregisterNetworkCallback(callback) connectivityManager.unregisterNetworkCallback(callback)
}
} }
} }
.flowOn(ioDispatcher)
.conflate() .conflate()
@Suppress("DEPRECATION") @Suppress("DEPRECATION")

Loading…
Cancel
Save