¿Dónde debo colocar el código para observar la conexión a internet para que el usuario sea notificado si el dispositivo está en línea o fuera de línea?
Tengo el código para monitorear si hay conexión a internet. Devuelve un LiveData y se observa en MainActivity. El código se muestra a continuación.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding=DataBindingUtil.setContentView(this,R.layout.activity_main)
NetworkStatusHelper(this@MainActivity).observe(this, Observer {
when(it){
NetworkStatus.Available-> Snackbar.make(binding.root, "De vuelta en línea", Snackbar.LENGTH_LONG).show()
NetworkStatus.Unavailable-> Snackbar.make(binding.root, "Sin conexión a internet", Snackbar.LENGTH_LONG).show()
}
})
}
NetworkHelper
package com.todo.utils.networkhelper
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import android.util.Log
import androidx.lifecycle.LiveData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.Socket
class NetworkStatusHelper(private val context: Context): LiveData<networkstatus>() {
var connectivityManager: ConnectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
private lateinit var connectivityManagerCallback: ConnectivityManager.NetworkCallback
val validNetworkConnections: ArrayList<network> = ArrayList()
fun getConnectivityCallbacks() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
val networkCapability =
connectivityManager.getNetworkCapabilities(network)
val hasNetworkConnection =
networkCapability?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
?: false
if (hasNetworkConnection) {
determineInternetAccess(network)
}
}
override fun onLost(network: Network) {
super.onLost(network)
validNetworkConnections.remove(network)
announceNetworkStatus()
}
private fun determineInternetAccess(network: Network) {
CoroutineScope(Dispatchers.IO).launch {
if (InternetAvailability.check()) {
withContext(Dispatchers.Main) {
validNetworkConnections.add(network)
announceNetworkStatus()
}
}
}
}
fun announceNetworkStatus() {
if (validNetworkConnections.isNotEmpty()) {
postValue(NetworkStatus.Available)
} else {
postValue(NetworkStatus.Unavailable)
}
}
}
} else {
TODO("VERSION.SDK_INT < LOLLIPOP")
}
override fun onActive() {
super.onActive()
connectivityManagerCallback = getConnectivityCallbacks()
val networkRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
NetworkRequest
.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
} else {
TODO("VERSION.SDK_INT < LOLLIPOP")
}
connectivityManager.registerNetworkCallback(networkRequest, connectivityManagerCallback)
}
override fun onInactive() {
super.onInactive()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
connectivityManager.unregisterNetworkCallback(connectivityManagerCallback)
}
}
object InternetAvailability {
fun check() : Boolean {
return try {
val socket = Socket()
socket.connect(InetSocketAddress("8.8.8.8",53))
socket.close()
true
} catch ( e: Exception){
e.printStackTrace()
false
}
}
}
}
El problema aquí es que se muestra la Snackbar incluso cuando la aplicación se abre por primera vez. No quiero que aparezca la Snackbar cuando la aplicación se abra por primera vez en la red. Si la red no está disponible, entonces la Snackbar debería aparecer incluso cuando se abra por primera vez la aplicación.
¿Alguien puede ayudar a mejorar el código con la lógica correcta para implementar esto?
davy.ai
Para resolver el problema, puede agregar una bandera booleana para llevar un registro de si se ha mostrado o no el Snackbar. Puede establecer esta bandera en verdadero después de que se muestre el Snackbar por primera vez. Luego, en el observador, puede verificar la bandera antes de mostrar el Snackbar. Aquí está el código actualizado:
Con estos cambios, el Snackbar no se mostrará cuando se abra la aplicación por primera vez y la red esté disponible. El Snackbar se mostrará si la red no está disponible o si no lo está cuando se abra la aplicación por primera vez.