使用 ConnectivityManager (传统方法,适用于所有 Android 版本)
这是最核心、最官方的方法,从 Android 7.0 (API 24) 开始,推荐使用 NetworkCallback 来进行监听,因为它更高效,只在网络状态变化时回调,而不是像广播那样一直处于活跃状态。

权限声明
在 AndroidManifest.xml 中必须声明网络访问权限。
<!-- 允许应用访问网络 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 从 Android 9 (API 28) 开始,如果需要监听网络变化,还需要此权限 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
在 Activity 或 Service 中实现监听
以下是一个完整的 Activity 示例,展示了如何注册和注销网络监听。
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.LinkProperties
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import android.os.Bundle
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
class NetworkActivity : AppCompatActivity() {
private lateinit var tvNetworkStatus: TextView
private lateinit var connectivityManager: ConnectivityManager
// 用于请求运行时权限
private val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
if (isGranted) {
// 权限被授予,可以开始监听网络
registerNetworkCallback()
} else {
// 权限被拒绝,提示用户
Toast.makeText(this, "网络权限被拒绝,无法监听网络状态", Toast.LENGTH_SHORT).show()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_network)
tvNetworkStatus = findViewById(R.id.tv_network_status)
connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
// 检查并请求权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
when {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_NETWORK_STATE
) == PackageManager.PERMISSION_GRANTED -> {
// 权限已授予,直接开始监听
registerNetworkCallback()
}
else -> {
// 请求权限
requestPermissionLauncher.launch(Manifest.permission.ACCESS_NETWORK_STATE)
}
}
} else {
// 对于低于 Android 6.0 的版本,不需要运行时权限
registerNetworkCallback()
}
}
/**
* 注册网络监听回调
*/
private fun registerNetworkCallback() {
// 创建一个网络请求构建器
val networkRequest = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) // 必须能上网
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) // 网络已连接可用
.build()
// 创建网络回调
val networkCallback = object : ConnectivityManager.NetworkCallback() {
// 网络可用时调用
override fun onAvailable(network: Network) {
super.onAvailable(network)
runOnUiThread {
tvNetworkStatus.text = "网络已连接"
Toast.makeText(this@NetworkActivity, "网络已连接", Toast.LENGTH_SHORT).show()
}
}
// 网络丢失时调用
override fun onLost(network: Network) {
super.onLost(network)
runOnUiThread {
tvNetworkStatus.text = "网络已断开"
Toast.makeText(this@NetworkActivity, "网络已断开", Toast.LENGTH_SHORT).show()
}
}
// 网络能力发生变化时调用(从 WiFi 切换到移动数据)
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, networkCapabilities)
val isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
val isMobile = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
runOnUiThread {
val networkType = when {
isWifi -> "WiFi"
isMobile -> "移动数据"
else -> "其他网络"
}
tvNetworkStatus.text = "网络已连接,类型: $networkType"
}
}
// 当网络的链接属性(如 IP 地址)发生变化时调用
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
super.onLinkPropertiesChanged(network, linkProperties)
// 可以在这里获取 IP 地址等信息
// println("Link properties changed: ${linkProperties.dnsServers}")
}
}
// 注册回调
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
}
/**
* 注销网络监听回调,防止内存泄漏
*/
private fun unregisterNetworkCallback() {
try {
connectivityManager.unregisterNetworkCallback(
// 注意:这里需要使用同一个 callback 实例
// 在实际项目中,最好将 callback 声明为成员变量
object : ConnectivityManager.NetworkCallback() {}
// 注意:上面的写法是错误的,只是为了演示,你应该保存 networkCallback 的引用。
// 正确做法是在 registerNetworkCallback 时创建并保存 callback 实例。
)
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun onDestroy() {
super.onDestroy()
// 在 Activity 销毁时,务必注销回调
unregisterNetworkCallback()
}
}
代码解释:
NetworkRequest.Builder(): 用于构建一个网络请求,你可以指定你关心的网络类型(如TRANSPORT_WIFI)和能力(如NET_CAPABILITY_INTERNET)。ConnectivityManager.NetworkCallback: 这是一个抽象类,你需要重写它的方法来处理网络事件。onAvailable(Network): 当网络满足NetworkRequest的条件时被调用。onLost(Network): 当之前可用的网络丢失时被调用。onCapabilitiesChanged(...): 当网络的能力(如传输类型)发生变化时调用,这是判断当前是 WiFi 还是移动数据的关键。onLinkPropertiesChanged(...): 当网络的底层属性(如 IP 地址、DNS 服务器)改变时调用。
connectivityManager.registerNetworkCallback(): 注册回调,系统会根据你的NetworkRequest来匹配网络,并在状态变化时通知你。connectivityManager.unregisterNetworkCallback(): 非常重要! 在不再需要监听或组件(如 Activity)销毁时,必须注销回调,否则会导致内存泄漏。runOnUiThread: 因为网络回调是在后台线程中执行的,而更新 UI 必须在主线程中,所以需要切换到主线程。
使用 Jetpack Compose (现代方法)
如果你正在使用 Jetpack Compose 开发应用,可以使用 NetworkAware 提供的 rememberConnectivityState 来更简洁地获取网络状态。

添加依赖
在 build.gradle 文件中添加 Jetpack Compose 相关依赖。
// build.gradle (:app)
dependencies {
// ... 其他依赖
implementation "androidx.compose.runtime:runtime-livedata:1.5.4" // 或更新的版本
implementation "com.google.accompanist:accompanist-permissions:0.32.0" // 用于处理权限
}
编写 Composable 代码
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.content.ContextCompat
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.google.accompanist.permissions.shouldShowRationale
// 假设你有一个 NetworkMonitor 类来封装 ConnectivityManager 逻辑
// 这是一个简化的示例,实际项目中你可能需要更复杂的封装
class NetworkMonitor(private val context: Context) {
private val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val isNetworkAvailable: Boolean
get() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val activeNetwork = connectivityManager.activeNetwork
val caps = connectivityManager.getNetworkCapabilities(activeNetwork)
return caps != null && caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
} else {
// 兼容旧版本
@Suppress("DEPRECATION")
val info = connectivityManager.activeNetworkInfo
return info != null && info.isConnected
}
}
}
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun NetworkStatusScreen() {
val context = LocalContext.current
val networkMonitor = remember { NetworkMonitor(context) }
// 使用 Accompanist 权限库管理 ACCESS_NETWORK_STATE 权限
val networkPermissionState = rememberPermissionState(permission = Manifest.permission.ACCESS_NETWORK_STATE)
// 使用 remember 来持有网络状态,避免重复创建
val isNetworkAvailable by remember(networkPermissionState.status) {
mutableStateOf(networkMonitor.isNetworkAvailable)
}
// 当权限状态改变时,更新网络状态
LaunchedEffect(key1 = networkPermissionState.status) {
if (networkPermissionState.status.isGranted) {
// 权限已授予,可以检查网络状态
// 这里的逻辑已经在 remember 中处理了,LaunchedEffect 主要用于副作用
}
}
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// 显示权限请求 rationale
if (networkPermissionState.status.shouldShowRationale) {
Text("需要网络权限来监听网络状态。")
}
// 显示网络状态
Text(
text = if (isNetworkAvailable) "网络已连接" else "网络未连接",
// 根据网络状态改变颜色
// color = if (isNetworkAvailable) Color.Green else Color.Red
)
}
}
@Preview(showBackground = true)
@Composable
fun NetworkStatusScreenPreview() {
NetworkStatusScreen()
}
代码解释:
NetworkMonitor类: 这是一个封装类,将ConnectivityManager的逻辑隐藏起来,方便在 Composable 中使用,它提供了一个isNetworkAvailable属性来获取当前网络是否可用。rememberPermissionState: 来自 Accompanist 权限库,用于简化运行时权限的请求和管理。remember: 用于在 Composable 生命周期内记住一个状态,这里我们用它来创建和持有NetworkMonitor实例,并记住isNetworkAvailable的值。LaunchedEffect: 用于在 Composable 中执行副作用,比如在权限状态变化时执行某些操作。collectAsStateWithLifecycle: 如果你的网络状态是通过LiveData或StateFlow提供的,这个函数非常有用,它能确保状态只在组件活跃时被收集,避免不必要的更新。
总结与对比
| 特性 | ConnectivityManager (传统方法) |
Jetpack Compose (现代方法) |
|---|---|---|
| 适用场景 | 所有 Android 项目,无论是否使用 Compose | 专门为 Jetpack Compose 设计 |
| 优点 | 官方标准,功能强大,可获取详细信息(网络类型、IP等) | 代码更简洁,声明式,与 Compose 生命周期完美集成 |
| 缺点 | 代码相对繁琐,需要手动处理线程切换和回调注销 | 依赖第三方库,封装性要求高,底层仍然是 ConnectivityManager |
| 核心API | ConnectivityManager, NetworkCallback |
rememberConnectivityState (通常需要自己封装) |
如何选择?
- 如果你正在开发一个使用传统 View 系统的 App,或者你需要非常精细地控制网络监听逻辑(只监听 WiFi 的变化),使用
ConnectivityManager是最佳选择。 - 如果你正在使用 Jetpack Compose,强烈建议使用 Compose 的方式,你可以自己封装一个类似
NetworkMonitor的类,或者使用社区中成熟的库(如kotlinx.coroutines的flow结合BroadcastReceiver)来提供网络状态流,然后在 Composable 中订阅这个流。
无论使用哪种方法,注销回调和处理运行时权限都是至关重要的,否则会导致内存泄漏或应用崩溃。
