23、WiFi与移动网络协同:同时使用WiFi与蜂窝数据(多路径)、NetworkCallback监听网络切换、粘性WiFi策略
这一章,我们来聊聊Android里一个挺有意思的话题——WiFi和蜂窝数据怎么“和平共处”。
说实话,早年做Android开发时,我总觉得这两个东西是“有你没我”的关系。WiFi连上了,蜂窝就歇着;WiFi断了,蜂窝才顶上。但后来发现,用户的需求远不止这么简单。比如你在下载一个大文件,WiFi信号突然变弱了,难道要等断流了再切4G?那体验也太差了。
所以,Android从某个版本开始,就引入了多路径传输、网络监听和粘性WiFi这些机制。说白了,就是让系统更聪明地管理网络资源。
23.1 多路径传输:同时用WiFi和蜂窝
多路径传输,英文叫Multipath。它的核心思想是:不把鸡蛋放在一个篮子里。
我参与过一个视频会议App的项目。用户经常抱怨,在办公室走动时,WiFi信号忽强忽弱,视频就卡住了。后来我们用了多路径方案,效果立竿见影。
核心原理:Android允许应用同时绑定WiFi和蜂窝网络。数据包可以走两条路,哪条快就走哪条。
实现方式主要有两种:
- 系统级多路径:Android 5.0+ 支持多网络同时连接,但默认只路由一个。需要应用主动请求。
- 应用级多路径:通过
Network对象手动绑定Socket,自己控制数据流向。
来看一段代码,怎么同时绑定两个网络:
// 获取 ConnectivityManager
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
// 请求WiFi网络
NetworkRequest wifiRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
// 请求蜂窝网络
NetworkRequest cellularRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build();
// 分别绑定
cm.requestNetwork(wifiRequest, wifiCallback);
cm.requestNetwork(cellularRequest, cellularCallback);
嗯,这里要注意:不是所有设备都支持同时绑定。有些厂商的定制ROM会限制这个行为。我在测试时就踩过这个坑——小米某款机型上,蜂窝网络绑定后根本拿不到数据。
避坑指南:我曾经在华为P30上测试多路径,发现蜂窝网络绑定后,Socket发送数据会超时。后来查了日志,发现是系统限制了非活动网络的带宽。解决办法是:在绑定后主动调用 Network.bindSocket() 并设置 SO_PRIORITY。
23.2 NetworkCallback:监听网络切换
网络切换,说白了就是WiFi和蜂窝之间“交接班”。但怎么知道什么时候该切换?
Android提供了 NetworkCallback 回调。我个人习惯用这个来监听网络状态变化,比轮询 getActiveNetworkInfo() 优雅多了。
来看一个完整的监听示例:
ConnectivityManager.NetworkCallback callback =
new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
// 网络可用
Log.d("NetCallback", "网络来了: " + network);
}
@Override
public void onLost(Network network) {
// 网络断开
Log.d("NetCallback", "网络丢了: " + network);
}
@Override
public void onCapabilitiesChanged(Network network,
NetworkCapabilities capabilities) {
// 网络能力变化,比如WiFi信号变弱
boolean hasWifi = capabilities
.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
boolean hasCellular = capabilities
.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
Log.d("NetCallback", "WiFi: " + hasWifi + ", 蜂窝: " + hasCellular);
}
@Override
public void onLinkPropertiesChanged(Network network,
LinkProperties linkProperties) {
// 链路属性变化,比如IP地址变了
Log.d("NetCallback", "链路变了: " + linkProperties);
}
};
// 注册监听
NetworkRequest request = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
cm.registerNetworkCallback(request, callback);
你想想看,这个回调能帮我们做什么?
- onAvailable:网络刚连上,可以开始传输数据了。
- onLost:网络断了,赶紧切到备用网络。
- onCapabilitiesChanged:WiFi信号从强变弱,可以提前准备切换。
- onLinkPropertiesChanged:IP变了,需要重新建立连接。
我的经验:在 onCapabilitiesChanged 里判断WiFi信号强度,比用 WifiManager 的 getRssi() 更靠谱。因为前者是系统统一管理的,后者可能因为权限问题拿不到。
23.3 粘性WiFi策略:让WiFi“赖着不走”
粘性WiFi,英文叫Sticky WiFi。这个策略很有意思——系统会尽量保持WiFi连接,即使信号已经很差了。
为什么会这样?
我记得有一次用户反馈:手机在客厅和卧室之间走动,WiFi信号从-50dBm掉到-80dBm,系统就是不切4G。用户觉得是Bug,但其实这是Google的设计哲学——WiFi优先,因为WiFi通常更便宜、更稳定。
粘性WiFi的实现机制:
- 信号阈值:系统有一个“粘性阈值”,比如-85dBm。低于这个值才会考虑切蜂窝。
- 切换延迟:即使信号低于阈值,系统也会等几秒钟,看看信号会不会恢复。
- 网络评分:Android 7.0+ 引入了网络评分机制。WiFi和蜂窝各有评分,系统选分数高的。
来看一张流程图,展示粘性WiFi的决策逻辑:
从流程图可以看出,粘性WiFi的核心就是“能忍则忍”。系统会尽量让WiFi多撑一会儿,实在不行了才切蜂窝。
注意:粘性WiFi策略在某些场景下会带来问题。比如用户在看视频,WiFi信号很差但系统不切4G,视频就会一直缓冲。我曾经在某个直播App里遇到过,用户骂我们“卡成PPT”,其实是系统策略的问题。
解决办法是什么?
应用可以主动干预。通过 NetworkCallback 的 onCapabilitiesChanged 判断信号强度,如果太差,就主动请求蜂窝网络:
@Override
public void onCapabilitiesChanged(Network network,
NetworkCapabilities capabilities) {
int wifiSignalStrength = capabilities
.getSignalStrength();
// 信号强度低于-80dBm,主动请求蜂窝
if (wifiSignalStrength < -80) {
NetworkRequest cellularRequest =
new NetworkRequest.Builder()
.addTransportType(
NetworkCapabilities.TRANSPORT_CELLULAR)
.build();
cm.requestNetwork(cellularRequest, cellularCallback);
}
}
嗯,这里有个细节:getSignalStrength() 返回的是0-4的整数,不是dBm。需要自己换算。我一般用这个公式:dBm = -100 + (signalStrength * 5)。当然,不同厂商可能有差异,最好在真机上测一下。
23.4 总结一下
这一章我们聊了三个核心点:
- 多路径传输:同时绑定WiFi和蜂窝,数据走最优路径。
- NetworkCallback:监听网络状态变化,及时响应。
- 粘性WiFi:系统优先保持WiFi,信号差也不轻易切。
说实话,这三个机制在实际项目中非常实用。尤其是做视频、直播、下载类App,网络切换的体验直接影响用户留存。我个人建议,不要完全依赖系统默认策略,应用层一定要有自己的网络监控和切换逻辑。
最后,留个思考题:如果你的App需要同时下载大文件和保持低延迟通话,你会怎么设计网络策略?欢迎在实践中摸索。
公众号:蓝海资料掘金营,微信deep3321