对于面向较新 Android 版本(API 21+)的应用,Google 推荐使用 ConnectivityManager.NetworkCallback 来监听网络变化。它提供了更精细的回调,能更准确地响应特定网络的能力变化(包括IP地址的变更),性能也更好。
NetworkCallback 提供了诸如 onAvailable(), onLost(), onCapabilitiesChanged() 等回调方法,可以精确地知道网络何时可用、何时丢失以及网络属性何时发生变化。
一、NetworkCallback 监听方式
ConnectivityManager 提供是注册监听和取消注册监听的方式如下:
- requestNetwork(NetworkRequest, NetworkCallback)
- registerNetworkCallback(NetworkRequest, NetworkCallback)
- registerDefaultNetworkCallback(NetworkCallback)
- unregisterNetworkCallback(NetworkCallback)
其中:
• registerNetworkCallback(监听模式):被动监听。只要符合条件的网络出现或状态改变就会通知你,但不会为了你的请求而主动保持网络连接,这是最常用的方式。
• requestNetwork(请求模式):主动请求。系统会尽力为你维持一个满足条件的网络连接。这会带来更显著的电量和资源消耗,通常用于执行关键、紧急的网络任务。
这里主要使用注册方式如下,主要是是否带 NetworkRequest 参数的网络条件的限制:
registerNetworkCallback(NetworkRequest, NetworkCallback) 这个方法让你能够精细地控制你想监听哪种类型的网络。你可以构建一个 NetworkRequest,要求网络必须具备某些能力(例如 NET_CAPABILITY_INTERNET 表示能访问互联网,NET_CAPABILITY_VALIDATED 表示已成功验证连接性,TRANSPORT_WIFI 表示是 Wi-Fi 网络等)。
- 用途:适用于你需要关注特定网络类型、或者需要同时监控多个网络连接状态(例如,即使 Wi-Fi 在后台连接但不可用,也能知道移动网络是否可用)的场景。
- 示例场景:应用需要确保有一个经过验证的互联网连接,不论是 Wi-Fi 还是移动数据;或者应用只在连接到非计量(unmetered)网络时才进行大文件下载。
registerDefaultNetworkCallback(NetworkCallback) 这个方法是 registerNetworkCallback 的一个简化版本,专门用于监听系统当前用于主要数据流量(如普通网页浏览、API 请求)的“默认”网络。系统会根据内部逻辑(通常优先选择未计费、更快的网络)来决定哪个网络是默认网络。
- 用途:适用于大多数常见的应用场景,即你只关心用户当前“实际使用”的互联网连接状态。
- 示例场景:显示一个状态栏图标指示当前是否有互联网连接;在网络丢失时弹出提示。
| 特性 | registerNetworkCallback(NetworkRequest, NetworkCallback) | registerDefaultNetworkCallback(NetworkCallback) |
|---|---|---|
| 监听目标 | 监听所有符合特定 NetworkRequest 条件的网络。 | 仅监听系统当前选择的默认网络。 |
| 控制粒度 | 高。需要传入一个 NetworkRequest 对象来指定所需网络的特性(例如:Wi-Fi、蜂窝数据、是否已验证等)。 | 低。无需 NetworkRequest,系统自动确定默认网络。 |
| 触发时机 | 当有任何符合 NetworkRequest 的网络可用、丢失或能力改变时都会触发回调,即使它不是默认网络。 | 仅当设备的默认网络发生变化(例如从移动数据切换到 Wi-Fi,或默认网络丢失)时才会触发回调。 |
| API level | API level 21 (Lollipop) 及以上可用。 | API level 24 (Nougat) 及以上可用。 |
如果你只需要知道设备当前是否有可用的默认互联网连接,并且目标 API >= 24,使用 registerDefaultNetworkCallback() 更简洁方便,它监听系统当前用于所有主要数据流量的默认网络。它关注的是默认属性,而不是特定的网络类型或能力。如果你需要更高级别的控制,需要监听特定类型的网络,或者需要兼容 API 21-23,使用 registerNetworkCallback() 并传入一个定制的 NetworkRequest。
二、NetworkRequest 设置特定网络类型
在使用 NetworkRequest.Builder 时,可以通过添加传输类型(Transport Types)和网络能力(Capabilities)来精确定义所需的网络类型。
2.1 添加传输类型 (addTransportType)
你可以指定网络必须使用的物理层连接类型:
- NetworkCapabilities.TRANSPORT_WIFI: 表示需要 Wi-Fi 连接。
- NetworkCapabilities.TRANSPORT_CELLULAR: 表示需要蜂窝移动数据连接。
- NetworkCapabilities.TRANSPORT_ETHERNET: 表示需要以太网连接。
- NetworkCapabilities.TRANSPORT_BLUETOOTH: 表示需要蓝牙连接(如蓝牙共享网络)。
- NetworkCapabilities.TRANSPORT_VPN: 表示需要 VPN 连接。
2.2 添加网络能力 (addCapability)
你可以指定网络必须具备的功能或属性:
- NetworkCapabilities.NET_CAPABILITY_INTERNET: 表示网络能够访问互联网。
- NetworkCapabilities.NET_CAPABILITY_NOT_METERED: 表示这是一个非计量(不按流量计费)的网络(例如大多数家用 Wi-Fi)。
- NetworkCapabilities.NET_CAPABILITY_VALIDATED: 表示系统已成功验证此网络具备实际的互联网连接(例如,没有出现强制门户登录页面)。
- NetworkCapabilities.NET_CAPABILITY_TRUSTED: 表示网络是受信任的。
示例:仅监听已验证的 Wi-Fi 网络
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI) // 仅限 Wi-Fi
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) // 必须能访问互联网
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) // 必须已通过验证
.build();
构建一个空的 Builder (最宽泛的请求):创建一个不包含任何特定 addTransportType() 或 addCapability() 限制的 NetworkRequest。这将匹配所有可用的网络变化,而系统会决定哪一个成为默认网络。
NetworkRequest request = new NetworkRequest.Builder().build();
connectivityManager.registerNetworkCallback(request, mNetworkCallback);
大多数应用关心的是“是否有可用的互联网连接”,要求具备互联网能力是一种更实用的“默认”网络模拟方式。
NetworkRequest request = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) // 必须能访问互联网
// 可选:添加最常见的传输类型以确保广泛覆盖
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build();
三、NetworkCallback 使用示例
使用 NetworkCallback 在现代 Android 应用中监听网络变化的示例(适用于 API 21+,特别是 API 24+ 中的 registerDefaultNetworkCallback)如下:
1. 在 AndroidManifest.xml 中添加必要的权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
2. 定义 NetworkCallback
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.os.Build;
import android.util.Log;
public class MyNetworkCallback extends ConnectivityManager.NetworkCallback {
private static final String TAG = "MyNetworkCallback";
@Override
public void onAvailable(Network network) {
super.onAvailable(network);
// 网络已连接,可以进行网络操作
Log.d(TAG, "网络可用: " + network.toString());
}
@Override
public void onLost(Network network) {
super.onLost(network);
// 网络连接丢失
Log.d(TAG, "网络丢失: " + network.toString());
}
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
// 网络能力发生变化(例如,从 Wi-Fi 切换到移动数据)
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
Log.d(TAG, "当前使用 Wi-Fi");
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
Log.d(TAG, "当前使用移动数据");
}
}
}
3. 注册与注销 Callback
需要在 Activity 或 Service 中注册和注销此 Callback。可以使用 registerDefaultNetworkCallback 监听默认网络的变化(API 24+),或使用 registerNetworkCallback(NetworkRequest, …) 进行更精细的控制。
import android.content.Context;
import android.net.ConnectivityManager;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private ConnectivityManager connectivityManager;
private MyNetworkCallback networkCallback;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
networkCallback = new MyNetworkCallback();
// 注册默认网络回调
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // API 24+
connectivityManager.registerDefaultNetworkCallback(networkCallback);
} else {
// 对于 API < 24 的设备,仍需使用旧的 BroadcastReceiver 或其他兼容方案
// ... (此处省略兼容旧版本的代码)
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 确保注销 callback
if (connectivityManager != null && networkCallback != null) {
connectivityManager.unregisterNetworkCallback(networkCallback);
}
}
}
四、总结
ConnectivityManager.CONNECTIVITY_ACTION 是 Android 网络监听历史中的重要一页,但在现代 Android 开发中,它已经过时。为了构建健壮、高效且符合系统最佳实践的应用,应优先使用 ConnectivityManager.NetworkCallback,NetworkCallback 提供了更强大的功能和更好的性能,是未来 Android 网络操作的标准做法。
317

被折叠的 条评论
为什么被折叠?



