在Android开发中,监听网络状态是一项常见且重要的功能,它能够帮助应用根据当前网络连接情况(如Wi-Fi、移动数据、无网络等)调整行为,例如在无网络时提示用户、在有网络时自动同步数据等,Android系统提供了多种方式来实现网络状态监听,主要包括ConnectivityManager、NetworkCallback以及BroadcastReceiver等,下面将详细介绍这些方法的实现原理、使用场景及注意事项。

使用ConnectivityManager与NetworkInfo(已废弃,但需了解)
在Android 6.0(API 23)之前,通常通过ConnectivityManager的getNetworkInfo()方法获取NetworkInfo对象,进而判断网络状态。
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
// 网络可用
} else {
// 网络不可用
}
但此方法已在API 23中被标记为废弃,因为其无法实时监听网络变化,且无法精确区分网络类型(如Wi-Fi或移动数据),目前仅适用于兼容旧版本代码的场景。
使用BroadcastReceiver监听网络变化(静态注册与动态注册)
动态注册(推荐)
通过注册一个BroadcastReceiver来监听系统广播ConnectivityManager.CONNECTIVITY_ACTION,当网络状态变化时,系统会发送此广播,示例代码如下:
private BroadcastReceiver networkReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetworkInfo != null && activeNetworkInfo.isConnected()) {
// 网络已连接
} else {
// 网络断开
}
}
}
};
// 在Activity或Service中注册
registerReceiver(networkReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
// 务必在适当时候注销(如Activity的onDestroy中)
unregisterReceiver(networkReceiver);
优点:兼容性较好,支持Android 6.0以下版本。
缺点:静态注册(在AndroidManifest.xml中注册)在Android 8.0(API 26)后无法接收隐式广播,动态注册需手动管理生命周期。

静态注册(仅限Android 8.0以下)
在AndroidManifest.xml中声明:
<receiver android:name=".NetworkChangeReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
注意:Android 8.0及以上系统限制后台应用接收静态广播,因此不推荐在新项目中使用。
使用NetworkCallback(推荐,API 21+)
Android 5.0(API 21)引入了NetworkCallback机制,通过ConnectivityManager的requestNetwork()或registerNetworkCallback()方法注册回调,可以更精确地监听网络状态变化,并支持网络能力的细粒度判断(如网络类型、带宽等),示例代码如下:
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
// 网络可用
}
@Override
public void onLost(Network network) {
// 网络丢失
}
@Override
public void onUnavailable() {
// 网络不可用
}
};
// 注册回调
connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
// 注销回调(需在Activity/Service销毁时调用)
connectivityManager.unregisterNetworkCallback(networkCallback);
优点:支持实时回调、精确判断网络类型、性能更优(无需通过广播机制)。
缺点:仅适用于API 21及以上版本,需处理版本兼容性。

网络状态判断的常见场景与代码示例
| 场景 | 实现方法 |
|---|---|
| 判断是否有网络连接 | 使用NetworkCallback的onAvailable()或BroadcastReceiver的isActiveNetworkInfo() |
| 判断是否为Wi-Fi | 通过NetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) |
| 判断是否为移动数据 | 通过NetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) |
| 获取当前网络类型 | NetworkCapabilities.getNetworkType()或NetworkInfo.getType() |
注意事项
- 权限申请:需在AndroidManifest.xml中声明网络权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.INTERNET" />
- 后台网络限制:Android 6.0以上系统在后台运行时可能限制网络访问,需考虑JobScheduler或WorkManager处理后台网络任务。
- 网络切换处理:当网络从Wi-Fi切换到移动数据时,需确保应用能正确处理数据量或资费问题。
相关问答FAQs
问题1:为什么在Android 8.0及以上版本使用静态注册的BroadcastReceiver无法监听网络变化?
解答:从Android 8.0开始,系统对后台应用接收隐式广播进行了限制,以减少电量消耗和提升系统性能,静态注册的BroadcastReceiver属于隐式广播,因此无法在后台被正常触发,建议改用动态注册或NetworkCallback(API 21+)的方式监听网络变化。
问题2:如何区分当前网络是Wi-Fi还是移动数据?
解答:在NetworkCallback中,可以通过NetworkCapabilities的getTransportType()方法判断,
@Override
public void onAvailable(Network network) {
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
if (capabilities != null) {
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
// 当前为Wi-Fi
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
// 当前为移动数据
}
}
} 