1. 功能定义和原理
移动数据始终开启是一个系统设置,它允许移动数据连接在 WiFi 等高优先级网络活跃时继续保持连接和活跃。
工作模式:
关闭始终开启:
WiFi 连接 → 移动数据自动断开 ✗
开启始终开启:
WiFi 连接 + 移动数据 → 都保持连接 ✓
优势:
- 更快的网络切换(两个网络都活跃)
- 应用可以在 WiFi 和移动数据间灵活切换
- 降低网络延迟和中断
2. 设置存储 (ConnectivitySettingsManager)
// 常量定义
public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
// 读取设置
public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) {
final int enable = Settings.Global.getInt(
context.getContentResolver(),
MOBILE_DATA_ALWAYS_ON, // 全局设置键
(def ? 1 : 0)); // 默认值
return (enable != 0) ? true : false;
}
// 写入设置
public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) {
Settings.Global.putInt(
context.getContentResolver(),
MOBILE_DATA_ALWAYS_ON,
(enable ? 1 : 0)); // 1 = 开启,0 = 关闭
}
存储位置:
- 数据库:
Settings.Global(系统全局设置) - 键:
mobile_data_always_on - 值:0 (关闭) 或 1 (开启)
3. 连接服务实现 (ConnectivityService)
核心组件
// 移动数据的"始终开启"网络请求
private final NetworkRequest mDefaultMobileDataRequest;
// 该请求的信息
// 当设置为开启时,这个请求始终存在
// 当设置为关闭时,这个请求被撤销
初始化流程
// 创建移动数据的始终开启请求
mDefaultMobileDataRequest = createDefaultInternetRequestForTransport(
NetworkCapabilities.TRANSPORT_CELLULAR, // 仅 4G/5G
NetworkRequest.Type.BACKGROUND_REQUEST); // 后台请求
// 在系统就绪时配置
onSystemReady() {
// ...
// 根据设置创建网络请求
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
}
设置监听
private void registerSettingsCallbacks() {
// 监听 MOBILE_DATA_ALWAYS_ON 设置变更
mSettingsObserver.observe(
Settings.Global.getUriFor(
ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON),
EVENT_CONFIGURE_ALWAYS_ON_NETWORKS); // 触发重新配置
// 监听 WiFi 始终请求设置
mSettingsObserver.observe(
Settings.Global.getUriFor(
ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED),
EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
}
4. 动态配置机制
配置处理 (handleConfigureAlwaysOnNetworks)
Setting 改变
↓
EVENT_CONFIGURE_ALWAYS_ON_NETWORKS
↓
handleConfigureAlwaysOnNetworks()
├─ 检查 MOBILE_DATA_ALWAYS_ON 设置值
├─ 检查 WIFI_ALWAYS_REQUESTED 设置值
└─ 检查 config_vehicleInternalNetworkAlwaysRequested 配置值
核心代码:
private void handleConfigureAlwaysOnNetworks() {
// 处理移动数据始终开启
handleAlwaysOnNetworkRequest(
mDefaultMobileDataRequest,
ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON,
true /* defaultValue */); // 默认开启
// 处理 WiFi 始终请求
handleAlwaysOnNetworkRequest(
mDefaultWifiRequest,
ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED,
false /* defaultValue */); // 默认关闭
// 处理车辆内部网络
final boolean vehicleAlwaysRequested = mResources.get().getBoolean(
R.bool.config_vehicleInternalNetworkAlwaysRequested);
handleAlwaysOnNetworkRequest(mDefaultVehicleRequest, vehicleAlwaysRequested);
}
5. 网络请求管理
启用始终开启 (设置 ON)
private void handleAlwaysOnNetworkRequest(
NetworkRequest networkRequest,
boolean enable) {
// 检查请求是否已存在
final boolean isEnabled = (mNetworkRequests.get(networkRequest) != null);
// 如果状态已匹配,无需操作
if (enable == isEnabled) {
return;
}
// 启用:注册网络请求
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
Process.myUid(),
networkRequest,
null /* messenger */,
null /* binder */,
NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */));
}
// 禁用:释放网络请求
else {
handleReleaseNetworkRequest(
networkRequest,
Process.SYSTEM_UID,
false /* callOnUnavailable */);
}
}
6. 完整执行流程
用户打开设置
↓
更改 MOBILE_DATA_ALWAYS_ON 为 ON
↓
调用 ConnectivitySettingsManager.setMobileDataAlwaysOn()
↓
Settings.Global 数据库更新
↓
ContentObserver 检测到变更
↓
发送 EVENT_CONFIGURE_ALWAYS_ON_NETWORKS
↓
handleConfigureAlwaysOnNetworks()
↓
handleAlwaysOnNetworkRequest(mDefaultMobileDataRequest, true)
↓
handleRegisterNetworkRequest()
↓
在网络管理中注册 "CELLULAR + INTERNET" 请求
↓
ConnectivityService 确保移动数据网络始终活跃
↓
即使 WiFi 连接,移动数据仍保持活跃 ✓
7. 网络请求类型详解
mDefaultMobileDataRequest 的特性
// 创建始终开启请求
private NetworkRequest createDefaultInternetRequestForTransport(
int transportType,
NetworkRequest.Type type) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.clearAll();
netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); // 仅移动数据
netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type);
}
// 网络请求特性:
// - 类型:BACKGROUND_REQUEST(后台请求)
// - 优先级:低(不会抢占用户请求)
// - 持久性:始终存在(当设置开启时)
// - 作用:保持移动数据网络连接
8. 与其他功能的关系
移动数据始终开启
│
├─ WiFi 始终请求 (WIFI_ALWAYS_REQUESTED)
│ ├─ 类似机制,用于 WiFi 网络
│ └─ 优先级:WiFi > 移动数据
│
├─ 网络请求 (NetworkRequest)
│ ├─ 应用可以发起自己的网络请求
│ └─ 系统基于优先级选择最优网络
│
└─ 网络切换 (Network Switching)
├─ 两个网络都活跃时更快切换
└─ 应用可以在 WiFi/移动数据间灵活选择
9. 实际工作流程图
网络状态变化时序:
事件 1:只有移动数据连接
移动数据活跃 → 应用使用移动数据 ✓
事件 2:WiFi 连接上
│
├─ 移动数据始终开启 = OFF
│ → 移动数据断开 ✗
│ → 应用切换到 WiFi ✓
│ → 网络切换延迟较大
│
└─ 移动数据始终开启 = ON
→ 移动数据保持连接 ✓
→ WiFi 也连接 ✓
→ 应用可瞬间在两网间切换 ✓
→ 网络切换延迟极小
事件 3:WiFi 断开
│
├─ 移动数据始终开启 = OFF
│ → 移动数据已断开,需重新连接
│ → 恢复延迟:1-3 秒
│
└─ 移动数据始终开启 = ON
→ 移动数据已保持连接
→ 恢复延迟:几毫秒 ✓
10. 性能和电池影响
| 设置状态 | 电池消耗 | 网络延迟 | 使用场景 |
|---|---|---|---|
| 关闭 | ⬇️ 低 | ⬆️ 高(需重连) | 省电,偶尔使用 |
| 开启 | ⬆️ 中等 | ⬇️ 低(已连接) | 实时应用,视频通话 |
电池消耗主要来自:
- 保持无线电活跃
- 定期信号强度查询
- 网络数据包保活
总结
移动数据始终开启是一个智能网络管理功能:
- 存储层:全局设置
MOBILE_DATA_ALWAYS_ON - 监听层:ContentObserver 监测设置变更
- 请求层:通过 NetworkRequest 机制向 ConnectivityService 注册请求
- 执行层:ConnectivityService 确保移动网络始终活跃
- 结果:WiFi 和移动数据可同时连接,应用可无缝切换
这个设计体现了 Android 系统模块化、事件驱动的架构特点。