如何在 Android 中监听网络连接状态的变化?

解读

国内面试中,这道题几乎必问,因为它同时考察“系统广播机制”“权限模型”“生命周期感知”“省电合规”四个维度。面试官想确认:

  1. 你是否只会已被废弃的静态广播;
  2. 能否在 Android 8.0 之后用官方推荐方式存活;
  3. 是否了解国产 ROM 对后台广播的额外限制;
  4. 能否给出“无后台常驻、无耗电”的完整方案。
    回答时务必先讲“合规”,再讲“实现”,最后给出“性能与兼容”细节,否则会被追问“用户杀进程后你还能收到吗?”

知识点

  1. 系统广播:ConnectivityManager.CONNECTIVITY_ACTION 在 7.0 之后仅限动态注册;静态广播无法接收。
  2. 权限:Android 10- 只需 ACCESS_NETWORK_STATE;Android 11+ 若需判断“真实上网能力”必须追加 ACCESS_WIFI_STATE 与 INTERNET。
  3. 生命周期感知:推荐在 Activity/Fragment 或 LifecycleService 中注册,退出即注销,防止内存泄漏。
  4. 国产 ROM 限制:小米、华为、OPPO 对后台广播有额外省电拦截,需引导用户手动关闭“省电优化”或改用前台 Service+通知。
  5. 精准判断:仅监听广播只能拿到“连接类型”,需主动调用 ConnectivityManager.getNetworkCapabilities() 判断 NET_CAPABILITY_VALIDATED 才能确认“可上网”。
  6. 省电替代:Jetpack WorkManager 2.7+ 提供 NetworkType.CONNECTED 约束,可周期任务代替实时监听;对实时性要求不高场景优先使用。
  7. 折叠屏/多窗口:监听 NetworkCallback 时需传入对应 LifecycleOwner,防止屏幕旋转后重复注册导致泄漏。

答案

分三步给出“面试级”标准答案,可直接背诵:

第一步:声明权限
AndroidManifest.xml 中仅保留最小权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
若需检测“是否真正连网”,再追加 INTERNET 权限即可。

第二步:动态注册 NetworkCallback(API 21+ 统一方案)

class NetworkMonitor(private val context: Application) : DefaultLifecycleObserver {

    private val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    private val validNetwork = MutableStateFlow(false)

    private val callback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            val capabilities = cm.getNetworkCapabilities(network)
            val validated = capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) == true
            validNetwork.value = validated
        }
        override fun onLost(network: Network) {
            validNetwork.value = false
        }
    }

    fun observe(): StateFlow<Boolean> = validNetwork.asStateFlow()

    override fun onCreate(owner: LifecycleOwner) {
        val request = NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            .build()
        cm.registerNetworkCallback(request, callback)
    }

    override fun onDestroy(owner: LifecycleOwner) {
        cm.unregisterNetworkCallback(callback)
    }
}

在 Application 的 onCreate() 中
ProcessLifecycleOwner.get().lifecycle.addObserver(NetworkMonitor(this))
即可实现“全局唯一、生命周期感知、无后台耗电”的监听。

第三步:国产 ROM 兼容
若需要“被用户强杀后仍能恢复监听”,将 NetworkMonitor 移至前台 Service(startForeground)并在通知栏常驻“网络守护”通知,同时在设置页引导用户关闭电池优化,满足国内厂商后台存活要求。

拓展思考

  1. 实时性 vs 省电:如果业务只是“上传日志”,用 WorkManager 的 NetworkType.CONNECTED 即可,无需常驻监听。
  2. 多网络并发:Android 9+ 支持双 Wi-Fi、双蜂窝,NetworkCallback 会回调多次,需以“是否具备 NET_CAPABILITY_VALIDATED”为准,而不是简单计数。
  3. 安全合规:Android 13 引入 NEARBY_WIFI_DEVICES 权限,若监听 Wi-Fi 状态变更需动态申请,避免被应用商店下架。
  4. 单元测试:使用 androidx.arch.core.executor.testing.InstantTaskExecutorRule + Turbine 可对 StateFlow 进行虚拟网络切换测试,无需真机。