Cuando registramos una devolución de llamada de red usando el registerNetworkCallback
método, a veces no se activa y, a veces, sí activa un falso positivo:
- Si iniciamos una aplicación con conexión a Internet, el
onAvailable
método se activa.
- Pero si no hay conexión a Internet en el dispositivo cuando iniciamos una aplicación, no
NetworkCallback
se llama nada (es muy extraño debido a la p. 1)
- Si tenemos conexión wifi pero sin conexión a internet
onAvailable
se activa el método. Y creo que es un comportamiento falso positivo porque esperamos que la conexión a Internet se observe.
Como puede ver en el siguiente código, la conexión a Internet predeterminada está disponible y se activa solo si cambia. Sin desencadenantes falsos positivos.
Simplemente resuma esto y esta respuesta (pero solo para API> = 21):
class ConnectionManager @Inject constructor(
private val connectivityManager: ConnectivityManager,
private val disposable: CompositeDisposable,
private val singleTransformer: SingleTransformer<*, *>
) : LiveData<Boolean>() {
private var isNetworkAvailable = true
private val builder = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
private val callback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
ping()
}
override fun onLost(network: Network) {
ping()
}
}
private fun ping() {
disposable.add(
Single.fromCallable {
try {
val timeoutMs = 1500
val socket = Socket()
val socketAddress = InetSocketAddress("8.8.8.8", 53)
socket.connect(socketAddress, timeoutMs)
socket.close()
true
} catch (e: IOException) {
false
}
}
.compose(singleTransformer as SingleTransformer<Boolean, Boolean>)
.subscribeBy {
if (isNetworkAvailable != it){
value = it
isNetworkAvailable = it
}
}
)
}
override fun onActive() {
ping()
connectivityManager.registerNetworkCallback(builder.build(), callback)
}
override fun onInactive() {
disposable.clear()
connectivityManager.unregisterNetworkCallback(callback)
}
}
Cómo proporcionar las dependencias
@Provides
fun provideTransformer(): SingleTransformer<Boolean, Boolean> {
return SingleTransformer<Boolean, Boolean> { upstream: Single<Boolean> ->
upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
}
@Singleton
@Provides
fun provideConnectivityManager(context: Context): ConnectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
@Singleton
@Provides
fun provideConnectionManager(connectivityManager: ConnectivityManager, singleTransformer: SingleTransformer<Boolean, Boolean>): ConnectionManager =
ConnectionManager(connectivityManager, singleTransformer)
Y como usar:
@Inject
lateinit var connectionManager: ConnectionManager
//....
viewLifecycleOwner.observe(connectionManager) { isInternetAvailable ->
// TODO
}
targetSdkVersion
a N o más tarde?BroadcastReceiver
con elandroid.net.conn.CONNECTIVITY_CHANGE
filtro de intención incluso cuando apunte a API29, solo necesita registrarloApplication.OnCreate
. Simplemente no recibirá ninguna actualización cuando la aplicación esté cerrada.