下面我将从基础概念、系统推荐方案、传统方案、高级应用场景等多个方面,为你详细讲解 Android 网络监测。

核心概念:Android 网络类型
在监测之前,首先要了解 Android 主要的网络类型:
- Wi-Fi (WIFI):通过无线局域网连接。
- 移动数据 (MOBILE):包括 2G, 3G, 4G (LTE), 5G 等。
- 以太网 (ETHERNET):通过有线网线连接(常见于 Android TV 或部分开发板)。
- 蓝牙共享 (BLUETOOTH):通过蓝牙共享网络。
- VPN (VPN):通过虚拟专用网络连接。
- (已废弃) WIMAX:一种无线城域网技术,现已不常用。
- (已废弃) MOBILE_DUN:通过拨号连接网络。
从 Android 10 (API 29) 开始,为了保护用户隐私,系统不再允许应用直接获取到具体的移动网络类型(如 4G, 5G),应用只能通过 TelephonyManager 获取到 NetworkCapabilities.NET_CAPABILITY_NOT_METERED 来判断是否为按流量计费的网络。
现代化推荐方案:ConnectivityManager.NetworkCallback
这是 Android 7.0 (API 24) 引入的、目前最推荐的监听网络变化的方式,它采用回调机制,只在网络状态真正发生变化时通知你的应用,非常高效且省电。
工作原理
- 通过
ConnectivityManager注册一个NetworkCallback。 - 系统会根据你的回调类型(监听所有网络变化或仅监听可用网络)在合适的时机回调你的方法。
- 你可以在回调方法中执行相应的逻辑,如重新请求网络、显示提示等。
代码示例
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 android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
class NetworkMonitorActivity : AppCompatActivity() {
private lateinit var connectivityManager: ConnectivityManager
private lateinit var networkCallback: ConnectivityManager.NetworkCallback
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 1. 获取 ConnectivityManager 实例
connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
// 2. 创建 NetworkCallback
networkCallback = object : ConnectivityManager.NetworkCallback() {
// 网络可用时回调
override fun onAvailable(network: Network) {
super.onAvailable(network)
runOnUiThread {
Toast.makeText(this@NetworkMonitorActivity, "网络已连接", Toast.LENGTH_SHORT).show()
// 在这里可以执行网络请求等操作
}
}
// 网络丢失时回调
override fun onLost(network: Network) {
super.onLost(network)
runOnUiThread {
Toast.makeText(this@NetworkMonitorActivity, "网络已断开", Toast.LENGTH_SHORT).show()
// 在这里可以停止网络请求,显示断网提示等
}
}
// 网络能力发生变化时回调(从 Wi-Fi 切换到移动数据)
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, networkCapabilities)
val isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
val isMetered = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED).not()
runOnUiThread {
if (isWifi) {
Toast.makeText(this@NetworkMonitorActivity, "当前网络: Wi-Fi", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this@NetworkMonitorActivity, "当前网络: 移动数据", Toast.LENGTH_SHORT).show()
}
if (isMetered) {
Toast.makeText(this@NetworkMonitorActivity, "当前网络: 按流量计费", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this@NetworkMonitorActivity, "当前网络: 不按流量计费", Toast.LENGTH_SHORT).show()
}
}
}
}
// 3. 构建网络请求并注册回调
// 监听所有网络变化
val request = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) // 必须是互联网连接
.build()
// 注册回调
connectivityManager.registerNetworkCallback(request, networkCallback)
}
override fun onDestroy() {
super.onDestroy()
// 4. 在 Activity/Fragment 销毁时,必须注销回调,防止内存泄漏
connectivityManager.unregisterNetworkCallback(networkCallback)
}
}
关键点
- 权限:需要
ACCESS_NETWORK_STATE权限。 - 注册/注销:必须在组件销毁时(如
onDestroy)注销回调,否则会导致内存泄漏。 - 线程:网络回调的执行线程不是主线程,如果需要更新 UI,必须切换到主线程(如使用
runOnUiThread)。 - NetworkRequest:你可以通过
NetworkRequest.Builder精确指定你想监听的网络类型(只监听 Wi-Fi),但通常监听所有互联网连接即可。
传统方案:BroadcastReceiver (监听 CONNECTIVITY_ACTION)
在 NetworkCallback 出现之前,开发者通常通过监听 ConnectivityManager.CONNECTIVITY_ACTION 这个系统广播来获取网络变化,这种方式仍然可用,但不推荐用于新项目。

为什么不推荐?
- 效率低:每次网络状态变化,系统都会广播所有监听的应用,即使应用没有前台运行,也会被唤醒,耗电严重。
- 不准确:广播的
Intent中包含的网络信息可能不准确,尤其是在网络切换的瞬间。 - 生命周期管理复杂:需要动态注册和注销,容易出错。
代码示例 (仅作了解)
class NetworkReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == ConnectivityManager.CONNECTIVITY_ACTION) {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetworkInfo = connectivityManager.activeNetworkInfo
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=".NetworkReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
实战应用场景
检查当前网络是否可用
在执行网络请求前,先检查是否有网络连接。
fun isNetworkAvailable(context: Context): Boolean {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val network = connectivityManager.activeNetwork ?: return false
val activeNetwork = connectivityManager.getNetworkCapabilities(network) ?: return false
return when {
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} else {
// 兼容旧版本
@Suppress("DEPRECATION")
val networkInfo = connectivityManager.activeNetworkInfo
return networkInfo != null && networkInfo.isConnected
}
}
仅在 Wi-Fi 下执行大文件下载
这是一个非常常见的业务需求,可以有效节省用户流量。
fun shouldDownloadOverWifi(context: Context): Boolean {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val network = connectivityManager.activeNetwork ?: return false
val caps = connectivityManager.getNetworkCapabilities(network) ?: return false
// 检查是否为 Wi-Fi 并且不是按流量计费的
return caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
} else {
@Suppress("DEPRECATION")
val networkInfo = connectivityManager.activeNetworkInfo
return networkInfo != null &&
networkInfo.isConnected &&
networkInfo.type == ConnectivityManager.TYPE_WIFI
}
}
// 使用示例
if (shouldDownloadOverWifi(this)) {
// 开始下载大文件
downloadLargeFile()
} else {
// 提示用户仅在 Wi-Fi 下下载
Toast.makeText(this, "请在 Wi-Fi 环境下下载大文件", Toast.LENGTH_LONG).show()
}
实时显示网络状态(如 App 的设置页)
你可以结合 NetworkCallback 和一个 LiveData 或 StateFlow,在 ViewModel 中持有一个网络状态变量,UI 观察这个变量并实时更新。

// 在 ViewModel 中 private val _networkState = MutableLiveData<Boolean>() val networkState: LiveData<Boolean> = _networkState // 在 Activity/Fragment 中注册 NetworkCallback,并在回调中更新 _networkState.value
权限声明
别忘了在 AndroidManifest.xml 中添加必要的权限:
<!-- 必需:用于访问网络状态信息 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 可选:如果你的 App 需要使用移动网络(非必须,但建议有) --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| NetworkCallback | 推荐、高效、省电、信息丰富 | 需要手动管理注册/注销、API 较高 | 所有新项目,需要精确、实时监听网络变化的场景。 |
| BroadcastReceiver | 兼容性好、实现简单 | 不推荐、耗电、不准确、广播可能被限制 | 旧项目维护,或需要兼容 Android 7.0 以下的设备。 |
| 直接检查 | 简单、按需使用 | 只能获取瞬时状态,无法监听变化 | 在执行网络操作前进行一次性的网络检查。 |
对于现代 Android 开发,请优先使用 ConnectivityManager.NetworkCallback,它是 Google 官方推荐的最佳实践,能够让你的应用更高效、更省电,同时提供更准确的网络信息。
