Android ConnectivityManager回调异常:蜂窝网络onAvailable不触发
问题分析与解决方案
你的问题出在两个核心点:NetworkRequest配置缺失,以及对NetworkCallback回调触发时机的误解。
核心原因
- onAvailable仅触发网络从「不可用」变为「可用」的瞬间:当WiFi和蜂窝网络同时存在时,蜂窝网络本来就处于可用状态,关闭WiFi并不会让蜂窝网络触发「不可用到可用」的状态变化,因此不会触发onAvailable回调。
- 未指定正确的网络监听规则:如果注册回调时没有配置明确的NetworkRequest,系统可能只会监听默认网络的部分状态变化,导致无法感知到已存在的蜂窝网络。
修复步骤
1. 创建带完整条件的NetworkRequest
注册回调时,必须明确指定需要监听的网络类型和核心能力(比如互联网访问权限):
val networkRequest = NetworkRequest.Builder() // 要求网络具备互联网访问能力 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) // 同时监听WiFi和蜂窝网络 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .build()
2. 传入NetworkRequest注册回调
替换原有的默认注册方式,改用带规则的注册:
val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager connectivityManager.registerNetworkCallback(networkRequest, connectivityCallback)
3. 重写onDefaultNetworkChanged处理网络切换
当WiFi关闭后,系统会将默认网络切换到蜂窝,但此时蜂窝已处于可用状态,不会触发onAvailable。因此需要监听默认网络的切换事件:
private val connectivityCallback = object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { Log.debug("网络可用: $network") } override fun onLost(network: Network) { Log.debug("网络丢失: $network") } // 监听默认网络切换,处理WiFi转蜂窝的场景 override fun onDefaultNetworkChanged(network: Network?) { network?.let { val capabilities = connectivityManager.getNetworkCapabilities(it) if (capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true) { Log.debug("默认网络切换为可用网络: $it") // 在这里更新你的应用网络状态 } else { Log.debug("默认网络无互联网访问") } } ?: run { Log.debug("无默认网络") } } }
4. 初始状态检查
由于回调仅在网络变化时触发,注册回调前需要先检查当前网络状态,避免启动时误判:
connectivityManager.activeNetwork?.let { currentNetwork -> val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) if (capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true) { Log.debug("初始状态: 当前有可用网络") } else { Log.debug("初始状态: 当前网络无互联网访问") } } ?: run { Log.debug("初始状态: 无任何网络") }
额外注意事项
- 页面销毁或不再需要监听时,务必调用
connectivityManager.unregisterNetworkCallback(connectivityCallback)取消注册,避免内存泄漏。 - 若需区分WiFi/蜂窝网络类型,可通过
NetworkCapabilities.hasTransport()方法在回调中判断。
内容的提问来源于stack exchange,提问作者Tobias Reich
相关产品推荐
相关产品推荐

