Observar la conexión de la red de forma permamente usando el componente Livedata de los componentes de arquitectura de Android
Creando ConnectivityLiveData
Archivo original de ConnectivityLiveData le he modificado para que cuando se conecte a una red disponible, detecte si hay conexión saliente a internet usando ping al servidor de google
class ConnectivityLiveData internal constructor(private val connectivityManager: ConnectivityManager) : LiveData<Boolean>() {
private var lastValue: Boolean? = null
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
constructor(application: Application) : this(
application.getSystemService(Context.CONNECTIVITY_SERVICE)
as ConnectivityManager
)
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network?) {
oneTimeNotify()
}
override fun onLost(network: Network?) {
oneTimeNotify()
}
}
override fun onActive() {
super.onActive()
oneTimeNotify()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
connectivityManager.registerDefaultNetworkCallback(networkCallback)
} else {
val builder = NetworkRequest.Builder()
connectivityManager.registerNetworkCallback(builder.build(), networkCallback)
}
}
override fun onInactive() {
super.onInactive()
connectivityManager.unregisterNetworkCallback(networkCallback)
}
private fun oneTimeNotify() {
val newValue = isNetworkAvailable()
if (lastValue != newValue) {
postValue(newValue)
lastValue = newValue
}
}
private fun isNetworkAvailable(): Boolean {
//val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val activeNetwork = connectivityManager.activeNetwork ?: return false
val networkCapabilities =
connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
return when {
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true
networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} else {
val activeNetwork = connectivityManager.activeNetworkInfo ?: return false
return activeNetwork.isConnectedOrConnecting
}
}
}
He remplazado la función de detección de red ActiveNetwork porque Android Studio me lo marcaba como deprecated.
He añadido prevención de enviar el estado multiples veces, ahora con el método oneTimeNofity() solo se notifica si es diferente al anterior.
Si se desea solo detectar si la conexión es mediante wifi, dentro del métodoisNetworkAvailable remueve los networkCapabilities menos el NetworkCapabilities.TRANSPORT_WIFI
Implementando ConnectivityLiveData
El ViewModel
debe extenderse de AndroidViewModel
de esa forma se puede obtener el contexto de la aplicación necesario para obtener el ConnectivityManager
class MyViewModel(application: Application) : AndroidViewModel(application) {
val connectivity: LiveData<Boolean>
init {
connectivity = ConnectivityLiveData(application)
}
}
Observando el ConnectivityLiveData
Por último debemos crear el observador del estado de conectividad
private val mViewModel: MyViewModel by lazy {
ViewModelProvider(this@HomeFragment).get(MyViewModel::class.java)
}
...
mViewModel.connectivity .observe(viewLifecycleOwner, Observer {
it?.run {
if (it) {
Log.d(TAG, "Network ON")
} else {
Log.w(TAG, "Network OFF")
}
}
})