Si se requiere detectar la conexión a internet permamente y así tener un control cuando se pierde la conexión y informar el usuario, usando los componentes de arquitectura de Android combinando viewModel con LiveData
Creando ConnectivityOnlineLiveData
Usando la nuevas API ConnectivityManager.NetworkCallback()
para obtener la conectividad en combinación con LiveData
(de Android Architecture Components) podemos crear una maravillosa clase observable para proporcionar esta devolución de llamada de cambio de conectividad.
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
import android.Manifest
import android.app.Application
import android.content.Context
import android.net.*
import android.os.Build
import androidx.annotation.RequiresPermission
import androidx.lifecycle.LiveData
class ConnectivityOnlineLiveData internal constructor(private val connectivityManager: ConnectivityManager) : LiveData<Boolean>() {
private var lastValue: Boolean? = null
@RequiresPermission(allOf = [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()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH)
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
connectivityManager.registerNetworkCallback(builder.build(), networkCallback)
}
}
private fun oneTimeNotify() {
val newValue = isInternetOn()
if (lastValue != newValue) {
postValue(newValue)
lastValue = newValue
}
}
override fun onInactive() {
super.onInactive()
connectivityManager.unregisterNetworkCallback(networkCallback)
}
private fun isNetworkIsAvailable(): Boolean {
val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
return activeNetwork?.isConnected == true
}
@RequiresPermission(android.Manifest.permission.INTERNET)
private fun isInternetOn(): Boolean {
if (isNetworkIsAvailable()) {
try {
val p = Runtime.getRuntime().exec("ping -c 1 www.google.com")
val value = p.waitFor()
return value == 0
} catch (e: Exception) {
e.printStackTrace()
}
}
return false
}
}
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
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 = ConnectivityOnlineLiveData(application)
}
}
Observando el ConnectivityOneLiveData
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, "Internet ON")
} else {
Log.w(TAG, "Internet OFF")
}
}
})
Enlaces
- Git de la función general blog-connectivitylivedata-class.kt
Muchas gracias!
excelente aporte.
Me gustaMe gusta