睿诚科技协会

android 网络是否可用

在 Android 中检查网络是否可用,通常需要检查两个层面:网络连接是否存在网络是否可以正常访问

android 网络是否可用-图1
(图片来源网络,侵删)

这是一个非常重要且常见的任务,因为仅仅有网络连接(比如连上了Wi-Fi)不代表一定能上网(比如Wi-Fi需要登录认证)。

下面我将从简单到复杂,为你介绍几种检查网络的方法,并给出推荐的实践方案。


使用 ConnectivityManager (标准方法)

这是 Android 官方推荐的方法,用于获取网络连接状态。

检查网络连接是否存在

这个方法只能告诉你设备是否连接到了某个网络(Wi-Fi、移动数据等),但不能保证一定能上网。

android 网络是否可用-图2
(图片来源网络,侵删)
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
fun isNetworkConnected(context: Context): Boolean {
    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    // 对于 Android 10 (API 29) 及以上版本
    val activeNetwork: Network? = connectivityManager.activeNetwork
    return activeNetwork != null
}

注意:在 Android 9 (API 28) 及以下版本,activeNetwork 不可用,你需要使用旧方法:

// 适用于 Android 9 (API 28) 及以下
fun isNetworkConnectedLegacy(context: Context): Boolean {
    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val networkInfo = connectivityManager.activeNetworkInfo
    return networkInfo != null && networkInfo.isConnected
}

检查网络是否可以访问 (更可靠的方法)

为了确保网络是“活的”,你需要尝试进行一个实际的连接,Android 提供了 NetworkCapabilities 来检查网络的详细能力,并且推荐使用 ConnectivityManager.registerNetworkCallback 来监听网络变化。

使用 NetworkCapabilities (API 23+)

这个方法可以检查网络是否满足特定条件,比如是否有互联网访问能力。

import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
fun isInternetAvailable(context: Context): Boolean {
    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    // 对于 Android 10 (API 29) 及以上版本
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        val network = connectivityManager.activeNetwork ?: return false
        val activeNetworkCapabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
        return activeNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
               activeNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
    } else {
        // 对于 Android 9 (API 28) 及以下版本
        @Suppress("DEPRECATION")
        val networkInfo = connectivityManager.activeNetworkInfo
        return networkInfo != null && networkInfo.isConnected && networkInfo.isAvailable
    }
}
  • NET_CAPABILITY_INTERNET: 网络被配置为提供互联网连接。
  • NET_CAPABILITY_VALIDATED: 网络连接已成功验证可以访问互联网,这是比 isConnected 更可靠的指标。

执行 Ping 操作 (最可靠但最慢)

这是最准确的方法,因为它真的尝试去发送一个网络请求,但缺点是耗时较长,不能在主线程执行,并且可能会因为防火墙或策略限制而失败。

android 网络是否可用-图3
(图片来源网络,侵删)
import java.io.IOException
import java.net.InetSocketAddress
import java.net.Socket
// 在后台线程调用此方法
fun isInternetReachable(): Boolean {
    return try {
        val timeoutMs = 1500
        val socket = Socket()
        val socketAddress = InetSocketAddress("8.8.8.8", 53) // Google DNS
        socket.connect(socketAddress, timeoutMs)
        socket.close()
        true
    } catch (e: IOException) {
        false
    }
}
  • 为什么用 8.8.853 端口?
    • 8.8.8 是 Google 的公共 DNS 服务器,它通常稳定且可访问。
    • 端口 53 是 DNS 端口,通常防火墙很少会封锁这个端口,比尝试 80 (HTTP) 端口的成功率更高。

使用第三方库 (简化开发)

为了简化代码处理,特别是处理不同 Android 版本的兼容性问题,开发者通常会选择使用成熟的第三方库。

推荐:android-networking

这是一个功能强大的网络库,内置了网络状态检查功能。

添加依赖:

// build.gradle (Module: app)
implementation 'com.amitshekhar.android:android-networking:1.0.2'

初始化:Application 类的 onCreate() 方法中初始化。

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        AndroidNetworking.initialize(applicationContext)
    }
}

检查网络状态:

import com.androidnetworking.AndroidNetworking
import com.androidnetworking.error.ANError
// 检查网络是否可用,并自动处理不同版本
fun isNetworkAvailable(context: Context): Boolean {
    return AndroidNetworking.get("https://www.google.com") // 可以用任意一个可靠地址
        .setPriority(Priority.LOW)
        .build()
        .isStarted // 这个方法不会真正发送请求,只是检查连接
}
// 更可靠的方式:执行一个简单的 HEAD 请求来检查网络
fun isInternetReachableWithLibrary() {
    AndroidNetworking.head("https://www.google.com")
        .setPriority(Priority.LOW)
        .build()
        .setRequestListener { _, error ->
            if (error == null) {
                // 网络可用
                println("Internet is reachable")
            } else {
                // 网络不可用
                println("Internet is not reachable: ${error.errorDetail}")
            }
        }
}

最佳实践:结合使用 + 监听网络变化

一个健壮的应用应该能够:

  1. 在需要时检查网络状态
  2. 在后台持续监听网络变化,以便在网络恢复时自动重试失败的操作。

完整示例:监听网络变化的广播接收器

创建 NetworkChangeReceiver.kt

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
class NetworkChangeReceiver : BroadcastReceiver() {
    interface NetworkStateListener {
        fun onNetworkStateChanged(isConnected: Boolean)
    }
    private var listener: NetworkStateListener? = null
    fun setListener(listener: NetworkStateListener) {
        this.listener = listener
    }
    override fun onReceive(context: Context, intent: Intent?) {
        if (intent?.action == ConnectivityManager.CONNECTIVITY_ACTION) {
            val isConnected = isInternetAvailable(context) // 使用前面介绍的可靠方法
            listener?.onNetworkStateChanged(isConnected)
        }
    }
    // ... 这里可以放上前面 isInternetAvailable() 的实现 ...
}

ActivityService 中注册和注销

import android.content.IntentFilter
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity(), NetworkChangeReceiver.NetworkStateListener {
    private lateinit var networkChangeReceiver: NetworkChangeReceiver
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        networkChangeReceiver = NetworkChangeReceiver()
        networkChangeReceiver.setListener(this)
        // 注册广播接收器
        val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
        registerReceiver(networkChangeReceiver, filter)
    }
    override fun onDestroy() {
        super.onDestroy()
        // 注销广播接收器,防止内存泄漏
        unregisterReceiver(networkChangeReceiver)
    }
    override fun onNetworkStateChanged(isConnected: Boolean) {
        if (isConnected) {
            Toast.makeText(this, "网络已连接", Toast.LENGTH_SHORT).show()
            // 在这里可以重试之前失败的网络请求
        } else {
            Toast.makeText(this, "网络已断开", Toast.LENGTH_SHORT).show()
            // 在这里可以停止正在进行的网络请求,并提示用户
        }
    }
}
方法 优点 缺点 适用场景
ConnectivityManager 官方标准,无需额外依赖 处理多版本兼容性稍显繁琐 所有标准应用,推荐作为基础方案。
执行 Ping 最准确,能真实反映网络可达性 耗时较长,不能在主线程,可能被防火墙拦截 在关键操作前(如下载大文件前)进行一次最终确认。
第三方库 简化代码,提供高级功能(如自动重试) 增加项目依赖,可能引入未知问题 快速开发,特别是当你的应用网络逻辑复杂时。

推荐策略:

  1. 日常检查:使用 ConnectivityManager + NetworkCapabilities (方案一) 来快速判断网络是否可用。
  2. 关键操作前:在执行重要网络请求前,可以增加一个轻量级的 Ping 操作作为二次确认。
  3. 后台监听:实现一个 BroadcastReceiver 来持续监听网络变化,提升用户体验。
  4. 项目复杂时:考虑使用 android-networkingRetrofit + OkHttp 这样的成熟网络库,它们通常已经内置了健壮的网络状态处理机制。
分享:
扫描分享到社交APP
上一篇
下一篇