Android网络状态监听优化:应用首次打开有网时不弹出Snackbar提示
问题根因
当前代码的问题在于:
- LiveData会在首次观察者绑定后,把当前存储的状态回传给观察者,不管是不是首次启动,都会触发Snackbar弹出
- 没有区分「首次初始化的状态上报」和「后续网络变化的状态上报」两种场景
具体优化方案
1. (可选)修改NetworkStatusHelper,增加初始状态主动查询
这一步可以避免首次启动时等待网络回调延迟返回状态,提升体验:
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() override fun onActive() { super.onActive() // 新增:主动查询一次当前网络状态,避免等待回调延迟返回初始值 val currentNetworkAvailable = checkCurrentNetworkAvailable() if (currentNetworkAvailable) { postValue(NetworkStatus.Available) } else { postValue(NetworkStatus.Unavailable) } // 原有注册回调逻辑保持不变 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) } // 新增:同步检查当前网络是否可用的工具方法 private fun checkCurrentNetworkAvailable(): Boolean { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val activeNetwork = connectivityManager.activeNetwork ?: return false val capabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) } else { @Suppress("DEPRECATION") val activeNetworkInfo = connectivityManager.activeNetworkInfo ?: return false @Suppress("DEPRECATION") return activeNetworkInfo.isConnected } } // 其余原有代码保持不变 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 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 } } } }
2. 修改MainActivity的Observer逻辑,区分首次状态
仅需增加一个首次标记位即可实现需求逻辑:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding=DataBindingUtil.setContentView(this,R.layout.activity_main) // 新增:标记是否是首次接收网络状态 var isFirstNetworkStatus = true NetworkStatusHelper(this@MainActivity).observe(this, Observer { when(it){ NetworkStatus.Available-> { // 仅非首次的可用状态才弹出提示 if (!isFirstNetworkStatus) { Snackbar.make(binding.root, "Back online", Snackbar.LENGTH_LONG).show() } } NetworkStatus.Unavailable-> { // 无论是否首次,网络不可用都弹出提示 Snackbar.make(binding.root, "No Internet connection", Snackbar.LENGTH_LONG).show() } } // 首次状态处理完成后修改标记,后续都走正常触发逻辑 isFirstNetworkStatus = false }) }
效果验证
修改后完全符合需求:
- 首次打开网络可用:首次状态回调触发时标记位为true,可用分支不弹Snackbar,标记位修改为false
- 首次打开网络不可用:不可用分支不受标记位限制,直接弹出提示
- 后续网络状态切换:标记位已经为false,两种状态变化都会触发对应Snackbar提示
内容的提问来源于stack exchange,提问作者DroidBee
相关产品推荐
相关产品推荐

