es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿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?

Tags:  ,

Answer

  1. Avatar for 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:

    class NetworkStatusHelper(private val context: Context): LiveData<networkstatus>() {
    
        // agregar una bandera para llevar un registro de si se ha mostrado el Snackbar o no
        private var snackbarDisplayed = false
    
        ...
    
        override fun onActive() {
            super.onActive()
            connectivityManagerCallback = getConnectivityCallbacks()
    
            // verificar si la red ya está disponible antes de registrar el callback
            val activeNetworkInfo = connectivityManager.activeNetworkInfo
            val isNetworkAvailable = activeNetworkInfo != null && activeNetworkInfo.isConnected
            if (isNetworkAvailable) {
                // establecer la bandera en verdadero para que el Snackbar no se muestre cuando se abra la aplicación por primera vez
                snackbarDisplayed = true
            }
    
            val networkRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                ...
            } else {
                TODO("VERSION.SDK_INT < LOLLIPOP")
            }
            connectivityManager.registerNetworkCallback(networkRequest, connectivityManagerCallback)
        }
    
        ...
    
        override fun onChanged(networkStatus: NetworkStatus) {
    
            // verificar la bandera antes de mostrar el Snackbar
            if (!snackbarDisplayed && networkStatus == NetworkStatus.Available) {
                // establecer la bandera en verdadero después de mostrar el Snackbar por primera vez
                snackbarDisplayed = true
                return
            }
    
            when(networkStatus){
                NetworkStatus.Available-> Snackbar.make(binding.root, "Conexión restablecida", Snackbar.LENGTH_LONG).show()
                NetworkStatus.Unavailable-> Snackbar.make(binding.root, "Sin conexión a Internet", Snackbar.LENGTH_LONG).show()
            }
        }
    
    }
    

    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.

Comments are closed.