核心概念
在开始之前,你需要了解 Android 网络相关的几个核心类和概念:

(图片来源网络,侵删)
- ConnectivityManager: 这是系统级的服务,负责管理网络连接,所有关于网络状态的查询和请求都通过它来进行。
- NetworkCapabilities: 描述一个网络连接的能力,
NET_CAPABILITY_INTERNET: 是否能访问互联网。NET_CAPABILITY_VALIDATED: 连接是否已验证(已成功解析 DNS)。NET_CAPABILITY_NOT_METERED: 是否是非按流量计费的网络(如 Wi-Fi)。NET_CAPABILITY_NOT_ROAMING: 是否是非漫游网络。
- NetworkRequest: 用于请求一个满足特定条件的网络,你可以用它来注册一个网络回调。
- NetworkCallback: 这是一个抽象类,你通过实现它来接收网络状态变化的通知,这是现代推荐的方式。
使用 ConnectivityManager.NetworkCallback (推荐)
这是 Android 6.0 (API 23) 引入的、最灵活、最强大的方式,它允许你异步地、精确地监听网络状态的变化,而不会阻塞主线程。
优点
- 异步非阻塞: 不会像广播那样可能造成 ANR (Application Not Responding)。
- 精确控制: 你可以精确地定义你关心的网络类型(只关心 Wi-Fi 或移动数据)。
- 高效: 只在你注册的条件下发生变化时才会收到回调,减少了不必要的唤醒和电量消耗。
实现步骤
- 获取
ConnectivityManager实例。 - 创建一个
NetworkRequest,指定你关心的网络条件。 - 创建
NetworkCallback的子类,并重写onAvailable(),onLost(),onUnavailable()等方法。 - 注册和注销回调。
代码示例
添加权限 (AndroidManifest.xml)
<!-- 检查网络状态所需 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 如果你的 App 需要 Internet 权限,最好也加上 --> <uses-permission android:name="android.permission.INTERNET" />
创建一个 NetworkHelper 工具类
import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
public class NetworkHelper {
private final ConnectivityManager connectivityManager;
private final NetworkCallback networkCallback;
public NetworkHelper(Context context) {
this.connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
this.networkCallback = new NetworkCallback();
}
/**
* 注册网络状态监听
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void registerNetworkCallback() {
if (connectivityManager != null) {
// 创建一个网络请求,这里我们只关心能访问互联网的网络
NetworkRequest request = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
// 注册回调
connectivityManager.registerNetworkCallback(request, networkCallback);
}
}
/**
* 注销网络状态监听
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void unregisterNetworkCallback() {
if (connectivityManager != null) {
connectivityManager.unregisterNetworkCallback(networkCallback);
}
}
/**
* 检查当前是否有网络连接
*/
public boolean isNetworkAvailable() {
if (connectivityManager == null) {
return false;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Network network = connectivityManager.getActiveNetwork();
if (network == null) {
return false;
}
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
return capabilities != null &&
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
} else {
// 对于低于 Android 8.0 的版本,使用旧的方法
android.net.NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnected();
}
}
/**
* 获取当前网络类型
*/
public String getNetworkType() {
if (!isNetworkAvailable()) {
return "No Connection";
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Network network = connectivityManager.getActiveNetwork();
if (network == null) return "Unknown";
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
if (capabilities == null) return "Unknown";
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return "Wi-Fi";
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return "Cellular";
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
return "Ethernet";
}
} else {
// 旧版本方法
android.net.NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null) {
int type = networkInfo.getType();
if (type == ConnectivityManager.TYPE_WIFI) {
return "Wi-Fi";
} else if (type == ConnectivityManager.TYPE_MOBILE) {
return "Cellular";
} else if (type == ConnectivityManager.TYPE_ETHERNET) {
return "Ethernet";
}
}
}
return "Unknown";
}
private static class NetworkCallback extends ConnectivityManager.NetworkCallback {
@Override
public void onAvailable(@NonNull Network network) {
super.onAvailable(network);
// 网络可用时调用,Wi-Fi 或移动数据已连接
// 注意:这里不能保证网络一定可以访问互联网,通常需要配合 onCapabilitiesChanged 判断
System.out.println("NetworkCallback: Network is available.");
}
@Override
public void onLost(@NonNull Network network) {
super.onLost(network);
// 网络丢失时调用,Wi-Fi 断开或移动数据断开
System.out.println("NetworkCallback: Network is lost.");
}
@Override
public void onUnavailable() {
super.onUnavailable();
// 没有可用的网络满足你的请求时调用
System.out.println("NetworkCallback: Network is unavailable.");
}
@Override
public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
// 网络能力变化时调用,例如从无网络到有网络,或者网络类型改变
// 可以在这里精确判断网络是否真正可用
boolean hasInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
boolean isValidated = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
if (hasInternet && isValidated) {
System.out.println("NetworkCallback: Network is validated and has internet.");
}
}
}
}
在 Activity 或 Service 中使用

(图片来源网络,侵删)
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private NetworkHelper networkHelper;
private TextView networkStatusText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
networkHelper = new NetworkHelper(this);
networkStatusText = findViewById(R.id.network_status_text);
Button checkButton = findViewById(R.id.check_button);
checkButton.setOnClickListener(v -> {
if (networkHelper.isNetworkAvailable()) {
Toast.makeText(this, "网络已连接: " + networkHelper.getNetworkType(), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "网络未连接", Toast.LENGTH_SHORT).show();
}
});
updateNetworkStatus();
}
@Override
protected void onResume() {
super.onResume();
// 在 Activity 可见时注册监听
networkHelper.registerNetworkCallback();
}
@Override
protected void onPause() {
super.onPause();
// 在 Activity 不可见时注销监听,防止内存泄漏
networkHelper.unregisterNetworkCallback();
}
private void updateNetworkStatus() {
if (networkHelper.isNetworkAvailable()) {
networkStatusText.setText("当前网络: " + networkHelper.getNetworkType());
} else {
networkStatusText.setText("当前网络: 未连接");
}
}
}
使用 BroadcastReceiver (旧方法)
在 Android 8.0 (API 26) 之前,我们通常通过监听 ConnectivityManager.CONNECTIVITY_ACTION 广播来检测网络变化。
缺点
- 已过时: 从 Android 8.0 开始,隐式广播(不指定包名的广播)不再对后台应用有效。
- 阻塞主线程: 广播接收器在主线程执行,如果处理不当可能导致 ANR。
- 不够精确: 无法区分是哪种网络类型的变化。
代码示例 (仅作了解)
创建 BroadcastReceiver
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.widget.Toast;
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()) {
Toast.makeText(context, "网络已连接", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "网络已断开", Toast.LENGTH_SHORT).show();
}
}
}
}
在 AndroidManifest.xml 中注册
<receiver android:name=".NetworkChangeReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
使用 Jetpack WorkManager (后台任务)
如果你的需求是在网络恢复后执行一个后台任务(重新上传数据),WorkManager 是最佳选择,它可以监听网络状态的变化,并在条件满足时执行任务。

(图片来源网络,侵删)
优点
- 可靠: WorkManager 保证任务最终会执行,即使应用被杀死或手机重启。
- 灵活: 可以组合多种约束条件,如网络状态、充电状态、电量等。
代码示例
创建一个 Worker
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
public class NetworkAwareWorker extends Worker {
public NetworkAwareWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public Result doWork() {
// 在这里执行你的网络任务
Log.d("NetworkWorker", "Network is available, performing task...");
// 上传数据、同步信息等
return Result.success(); // 任务成功
}
}
在需要的地方设置并启动任务
import androidx.work.Constraints;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
// ...
// 创建约束条件:只有在有网络连接时才执行
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) // 或者 UNMETERED (仅非流量网络)
.build();
// 创建一次性任务请求
OneTimeWorkRequest uploadWorkRequest =
new OneTimeWorkRequest.Builder(NetworkAwareWorker.class)
.setConstraints(constraints)
.build();
// 提交任务
WorkManager.getInstance(context).enqueue(uploadWorkRequest);
总结与最佳实践
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
NetworkCallback |
现代、高效、精确、异步 | 需要 API 21+ | 绝大多数场景,特别是需要实时响应用户界面变化的场景。 |
BroadcastReceiver |
简单、兼容性好 | 已过时、不精确、可能无效 | 旧项目维护,或仅需兼容非常低版本的 API。 |
WorkManager |
可靠、适合后台任务 | 不适合实时 UI 更新 | 在网络恢复后执行一次性或周期性的后台任务。 |
最佳实践建议:
- 对于需要实时更新 UI 的场景(显示一个在线/离线的状态指示器),使用
ConnectivityManager.NetworkCallback,这是 Google 推荐的标准方式。 - 在 Activity/Fragment 的生命周期中管理回调:在
onResume()或onStart()中注册,在onPause()或onStop()中注销,以避免内存泄漏和不必要的电量消耗。 - 对于后台数据同步,使用 WorkManager,它能更好地处理任务调度和生命周期问题,确保数据最终能够同步成功。
- 避免在
BroadcastReceiver中执行耗时操作,否则很容易导致 ANR,如果必须处理,应启动一个 Service 或 IntentService 来完成。
