- 监听网络状态变化:如何实时知道网络已经断开或已连接。
- 检查当前网络状态:在执行网络操作前,主动检查网络是否可用。
- 更新 UI 和用户反馈:当网络断开时,如何通知用户。
- 处理后台任务:如果后台任务(如下载、上传)因网络中断而失败,应该如何处理。
监听网络状态变化 (核心)
在 Android 中,监听网络状态变化主要有两种方式:

使用 ConnectivityManager 和 NetworkCallback (推荐,API 24+)
这是 Android 7.0 (Nougat, API 24) 引入的现代化方式,它更高效、更灵活,因为它使用回调机制,而不是像广播那样需要全局监听。
关键类:
ConnectivityManager: 系统服务,用于管理网络连接。NetworkRequest: 描述你感兴趣的网络的请求。NetworkCallback: 当网络状态发生变化时,系统会回调这个类中的方法。
实现步骤:
-
获取 ConnectivityManager 实例:
(图片来源网络,侵删)ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
-
创建 NetworkRequest 和 NetworkCallback:
// 创建一个网络请求,我们关心所有类型的网络 NetworkRequest networkRequest = new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(); // 创建网络回调 ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() { @Override public void onLost(Network network) { // 网络连接丢失时调用 (从 WiFi 切换到移动数据,或 WiFi 断开) Log.d("NetworkCallback", "网络连接丢失"); runOnUiThread(() -> { // 在这里更新 UI,例如显示网络断开提示 Toast.makeText(MainActivity.this, "网络已断开", Toast.LENGTH_SHORT).show(); // 禁用需要网络的功能按钮 }); } @Override public void onAvailable(Network network) { // 网络连接可用时调用 Log.d("NetworkCallback", "网络连接可用"); runOnUiThread(() -> { // 在这里更新 UI,例如隐藏网络断开提示 Toast.makeText(MainActivity.this, "网络已连接", Toast.LENGTH_SHORT).show(); // 启用需要网络的功能按钮 }); } }; -
注册和注销回调:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ... 其他代码 ... // 注册网络回调 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { connectivityManager.registerNetworkCallback(networkRequest, networkCallback); } else { // 对于低于 API 24 的版本,需要使用广播的方式 (见下文) } } @Override protected void onDestroy() { super.onDestroy(); // 在 Activity 销毁时,必须注销回调,防止内存泄漏 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { connectivityManager.unregisterNetworkCallback(networkCallback); } }
使用 BroadcastReceiver (兼容旧版本)
这种方式在所有 Android 版本上都能工作,但缺点是它是一个全局广播,即使你的 App 在后台,只要系统发送广播,你的接收器就会被唤醒,可能会影响性能。
关键类:

BroadcastReceiver: 用于接收系统广播。ConnectivityManager: 系统服务。NetworkInfo: 描述网络连接的信息。
实现步骤:
-
创建一个
BroadcastReceiver:public class NetworkChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) { ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); if (activeNetworkInfo == null || !activeNetworkInfo.isConnected()) { // 网络未连接 Log.d("NetworkReceiver", "网络断开"); // 更新 UI 或执行其他操作 } else { // 网络已连接 Log.d("NetworkReceiver", "网络已连接"); } } } } -
在
AndroidManifest.xml中注册 Receiver:<receiver android:name=".NetworkChangeReceiver"> <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> </intent-filter> </receiver>注意:从 Android 7.0 (API 24) 开始,对
CONNECTIVITY_ACTION隐式广播的接收限制非常严格,如果你的targetSdkVersion是 24 或更高,上面的方式可能无法正常工作。对于新项目,强烈推荐使用NetworkCallback。
检查当前网络状态
除了监听变化,很多时候你还需要在执行网络请求前主动检查一下网络是否可用。
使用 ConnectivityManager:
public boolean isNetworkAvailable() {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
// 对于 API 23 及以上版本
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Network network = connectivityManager.getActiveNetwork();
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
if (capabilities != null) {
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET);
}
} else {
// 对于低于 API 23 的版本
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
}
return false;
}
使用示例:
if (isNetworkAvailable()) {
// 执行网络请求
makeNetworkRequest();
} else {
// 显示提示,告诉用户网络不可用
Toast.makeText(this, "网络不可用,请检查设置", Toast.LENGTH_SHORT).show();
}
更新 UI 和用户反馈
当检测到网络断开时,最佳实践是:
- Toast 或 SnackBar:显示一个简短的提示信息,告诉用户网络已断开。
- 禁用按钮:如果界面中有“上传”、“下载”、“刷新”等依赖网络的按钮,应将其设置为
setEnabled(false),防止用户误操作。 - 显示占位符:在列表或数据加载区域,显示一个“无网络连接”的占位图或文本。
- 数据缓存:App 有离线浏览的需求,可以提示用户“当前为离线模式,显示的是缓存数据”。
处理后台任务
如果你的 App 使用了 WorkManager、JobScheduler 或 AlarmManager 来执行后台任务,当网络断开时,任务应该被推迟或失败。
-
WorkManager (推荐): WorkManager 非常智能,你可以为你的
Worker指定网络约束。public class DownloadWorker extends Worker { public DownloadWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @NonNull @Override public Result doWork() { // 你的下载逻辑 // ... return Result.success(); // 或 Result.retry() } } // 在提交任务时设置约束 Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) // 只在连接时执行 .build(); OneTimeWorkRequest downloadWorkRequest = new OneTimeWorkRequest.Builder(DownloadWorker.class) .setConstraints(constraints) .build(); WorkManager.getInstance(context).enqueue(downloadWorkRequest);当网络断开时,WorkManager 会自动推迟
NetworkType.CONNECTED的任务,直到网络恢复。 -
其他库 (如 Retrofit + OkHttp): 对于网络请求库,通常会提供一个重试机制,当请求失败时,库可以自动重试几次,如果网络是断开的,这些重试也都会失败,你可以在你的代码逻辑中判断:如果请求失败,并且原因是网络问题,就提示用户,而不是立即重试。
完整代码示例 (NetworkCallback 方式)
这是一个在 Activity 中实现网络监听的完整示例。
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ConnectivityManager.NetworkCallback networkCallback;
private Button networkDependentButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
networkDependentButton = findViewById(R.id.btn_network_action);
networkDependentButton.setOnClickListener(v -> {
if (isNetworkAvailable()) {
Toast.makeText(this, "执行网络操作...", Toast.LENGTH_SHORT).show();
// makeNetworkRequest();
} else {
Toast.makeText(this, "网络不可用,无法操作", Toast.LENGTH_SHORT).show();
}
});
setupNetworkCallback();
}
private void setupNetworkCallback() {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager == null) return;
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onLost(Network network) {
Log.d("MainActivity", "网络连接丢失");
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "网络已断开", Toast.LENGTH_SHORT).show();
networkDependentButton.setEnabled(false);
});
}
@Override
public void onAvailable(Network network) {
Log.d("MainActivity", "网络连接可用");
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "网络已连接", Toast.LENGTH_SHORT).show();
networkDependentButton.setEnabled(true);
});
}
};
// 注册回调
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
} else {
// 对于旧版本,可以在这里注册广播接收器
// 但请注意 API 24+ 的限制
}
}
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Network network = connectivityManager.getActiveNetwork();
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
if (capabilities != null) {
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
}
} else {
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
}
return false;
}
@Override
protected void onDestroy() {
super.onDestroy();
if (networkCallback != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
connectivityManager.unregisterNetworkCallback(networkCallback);
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<Button
android:id="@+id/btn_network_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="执行网络操作" />
<TextView
android:id="@+id/tv_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="等待网络状态..." />
</LinearLayout>
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" />
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
NetworkCallback |
高效、灵活、现代化、只在你的应用上下文中回调,性能好。 | 仅适用于 API 24 及以上版本。 | 新项目的首选。 |
BroadcastReceiver |
兼容所有版本。 | 全局广播、性能开销大、在 API 24+ 上受限。 | 需要兼容旧版本 (API < 24) 的项目。 |
最佳实践建议:
- 主流程:使用
NetworkCallback监听网络状态变化,实时更新 UI。 - 前置检查:在每次执行网络请求前,使用
isNetworkAvailable()方法进行检查。 - 后台任务:使用
WorkManager并设置NetworkType约束,让系统智能地处理任务调度。 - 兼容性:如果你的
minSdkVersion低于 24,需要同时实现BroadcastReceiver作为备用方案,并在onCreate中根据版本选择使用哪种方式。
