睿诚科技协会

Android网络状态如何实时监测?

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

Android网络状态如何实时监测?-图1
(图片来源网络,侵删)

核心概念: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) 引入的、目前最推荐的监听网络变化的方式,它采用回调机制,只在网络状态真正发生变化时通知你的应用,非常高效且省电。

工作原理

  1. 通过 ConnectivityManager 注册一个 NetworkCallback
  2. 系统会根据你的回调类型(监听所有网络变化或仅监听可用网络)在合适的时机回调你的方法。
  3. 你可以在回调方法中执行相应的逻辑,如重新请求网络、显示提示等。

代码示例

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 这个系统广播来获取网络变化,这种方式仍然可用,但不推荐用于新项目。

Android网络状态如何实时监测?-图2
(图片来源网络,侵删)

为什么不推荐?

  1. 效率低:每次网络状态变化,系统都会广播所有监听的应用,即使应用没有前台运行,也会被唤醒,耗电严重。
  2. 不准确:广播的 Intent 中包含的网络信息可能不准确,尤其是在网络切换的瞬间。
  3. 生命周期管理复杂:需要动态注册和注销,容易出错。

代码示例 (仅作了解)

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 和一个 LiveDataStateFlow,在 ViewModel 中持有一个网络状态变量,UI 观察这个变量并实时更新。

Android网络状态如何实时监测?-图3
(图片来源网络,侵删)
// 在 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 官方推荐的最佳实践,能够让你的应用更高效、更省电,同时提供更准确的网络信息。

分享:
扫描分享到社交APP
上一篇
下一篇