Android:如何准确检测WiFi已完全连接?
解答Android WiFi切换中的状态不一致问题
我来帮你拆解这些WiFi API的异常行为问题,结合你的日志和代码逐一分析:
1. 为什么切换到NET3时会触发NET1的CONNECTED状态?
Android的WiFi状态广播并不是严格按照实时状态顺序触发的,在网络切换的瞬间,系统内部的状态同步存在延迟:
- 当你调用
disconnect()和enableNetwork(net3, true)后,系统首先会开始断开当前连接的NET1,但之前NET1的CONNECTED状态事件可能还在广播队列中等待分发,所以会先收到这条旧状态的日志。 - 后续的
DISCONNECTED, "NET1"才是NET1真正断开的事件,这是网络切换流程中的正常状态回调顺序。
2. 为什么NetworkInfo显示NET1,而getConnectionInfo()返回NET3?
这两个API的数据源完全不同:
NetworkInfo是当前广播事件对应的网络的状态快照,这里的事件是NET1断开前的收尾状态,所以显示NET1。WifiManager.getConnectionInfo()获取的是系统当前激活的网络配置,当你调用enableNetwork(net3, true)后,系统已经将NET3设为待连接的活跃配置,所以会直接返回NET3的信息,哪怕此时NET3还没真正连接上。
这种不一致是Android WiFi API设计的正常现象,不能混用来判断当前实际连接的网络。
3. 如何准确检测目标网络的连接状态?能否从NetworkInfo中提取SSID?
准确提取当前事件对应的SSID
你更新的代码思路是对的!不要用WifiManager.getConnectionInfo(),而是直接从广播Intent中获取WifiInfo,它才是当前事件对应的网络信息:
private final BroadcastReceiver mWifiConnectReceiver = new BroadcastReceiver() { @Override public void onReceive(Context c, Intent intent) { // 获取当前事件对应的NetworkInfo NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); // 获取当前事件对应的WifiInfo(关键!) WifiInfo wifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO); if (wifiInfo != null && info != null) { String ssid = wifiInfo.getSSID().replaceAll("^\"(.*)\"$", "$1"); Log.i("MyApp", "--------------------------"); Log.i("MyApp", info.getDetailedState() + ", SSID: " + ssid); // 检测目标网络(NET3)是否真正连接完成 if ("NET3".equals(ssid) && info.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) { // 此时可以获取IP地址,连接路由器Socket int ipAddress = wifiInfo.getIpAddress(); String localIp = String.format("%d.%d.%d.%d", (ipAddress & 0xff), (ipAddress >> 8 & 0xff), (ipAddress >> 16 & 0xff), (ipAddress >> 24 & 0xff)); Log.i("MyApp", "NET3已连接,本地IP:" + localIp); // 如果需要路由器网关IP,可以通过DhcpInfo获取 DhcpInfo dhcpInfo = m_manager.getDhcpInfo(); String gatewayIp = String.format("%d.%d.%d.%d", (dhcpInfo.gateway & 0xff), (dhcpInfo.gateway >> 8 & 0xff), (dhcpInfo.gateway >> 16 & 0xff), (dhcpInfo.gateway >> 24 & 0xff)); Log.i("MyApp", "路由器网关IP:" + gatewayIp); } } } };
准确检测目标网络连接状态的要点
- 只处理目标SSID的事件:过滤掉其他SSID的状态回调,避免被旧网络的状态干扰。
- 等待真正的CONNECTED状态:
CONNECTED状态出现后,还要确认WifiInfo的IP地址不为0(或者等待OBTAINING_IPADDR之后的CONNECTED),确保网络已经完成IP分配,此时才能正常连接路由器的Socket。 - 避免依赖全局的WifiManager状态:优先使用广播Intent中携带的
WifiInfo和NetworkInfo,它们是当前事件的精准快照,不会提前指向新网络。
内容的提问来源于stack exchange,提问作者folibis




