【网络优化】Android 如何监听系统网络连接成功

思路一句话:

"把『系统网络连接成功』当成一个系统广播事件,注册一个 ConnectivityManager.NetworkCallback(或者 legacy 的 BroadcastReceiver),一旦收到 『已连接且可上网』的回调,就启动协程/线程去调你的 API。"


  1. 权限(AndroidManifest.xml)
xml 复制代码
<!-- 普通权限,安装即授予 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 需要真正上网,别忘 INTERNET -->
<uses-permission android:name="android.permission.INTERNET" />

  1. 生命周期感知型 NetworkCallback(推荐)
kotlin 复制代码
class MyApp : Application() {

    override fun onCreate() {
        super.onCreate()
        NetworkProbe.init(this)
    }
}

object NetworkProbe {

    private val cm by lazy { app.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager }

    private lateinit var app: Application

    fun init(app: Application) {
        this.app = app
        // 兼容 O 以下
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            registerNetworkCallback()
        } else {
            registerLegacyReceiver()
        }
    }

    @TargetApi(Build.VERSION_CODES.N)
    private fun registerNetworkCallback() {
        val request = NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) // 已验证可上网
            .build()

        cm.registerNetworkCallback(
            request,
            object : ConnectivityManager.NetworkCallback() {

                // 第一次连接或网络恢复都会走到这里
                override fun onAvailable(network: Network) {
                    super.onAvailable(network)
                    callMyApi()
                }

                // 如果只想『从断网到联网』触发一次,可再覆写 onLost 做状态机
            }
        )
    }

    // 兼容低版本
    private fun registerLegacyReceiver() {
        val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
        app.registerReceiver(object : BroadcastReceiver() {
            override fun onReceive(c: Context, i: Intent) {
                val info = cm.activeNetworkInfo
                if (info?.isConnected == true) {
                    callMyApi()
                }
            }
        }, filter)
    }

    // 真正去调接口
    private fun callMyApi() {
        // 网络回调里不能做重 IO,切到 IO 线程
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val rsp = RetrofitClient.api.ping() // 你的 Retrofit 接口
                Log.d("NetworkProbe", "API 调用成功:$rsp")
                // 如果只想成功一次,可在这里 unregister 或者置标志位
            } catch (e: Exception) {
                Log.e("NetworkProbe", "API 失败", e)
            }
        }
    }
}

  1. 只想在『前台 Activity』里监听?
    LifecycleObserverregisterNetworkCallback 搬进 onResumeonPauseunregister 即可,避免后台重复触发。

  1. 常见坑提示
  • 不要把 onAvailable 当成"Wi-Fi 连上了",它只代表系统选中的默认网络变更;
    加上 NET_CAPABILITY_VALIDATED 可确保已经通过 204/443 探测,真正可上网。
  • 7.0+ 静态注册 CONNECTIVITY_ACTION 无效,必须动态注册或改用 NetworkCallback
  • 回调线程是 系统 Binder 线程,不能直接做网络 IO,务必切协程/线程池。
  • 如果用户处于 ** captive portal **(需要网页认证),VALIDATED 不会满足,API 也调不通,符合预期。

一句话总结

"注册 ConnectivityManager.NetworkCallback → 在 onAvailable()NET_CAPABILITY_VALIDATED 时切 IO 线程调你的接口" 。

相关推荐
稳联技术老娜2 小时前
DeviceNet主站怎么连接西门子PLC,Profinet网关配置手册(那智机器人)
服务器·网络·数据库
针叶3 小时前
Google Play加固保护导致的崩溃
android·安全·google
志栋智能4 小时前
AI驱动无代码:降低巡检超自动化的门槛
大数据·运维·网络·人工智能·自动化
专业机床数据采集4 小时前
C# 精雕数控 数据采集 Demo|实时读取精雕机床坐标、主轴、负载、加工工时全量参数
网络·网络协议·tcp/ip·mes·精雕数控数据采集
AOwhisky4 小时前
Ceph系列第六期:Ceph 文件系统(CephFS)精讲
linux·运维·网络·笔记·ceph
我爱C编程5 小时前
基于ECC簇内分组密钥管理算法的无线传感器网络matlab性能仿真
网络·matlab·ecc·密钥管理·无线传感器网络·簇内分组
执明wa5 小时前
Android Studio 项目目录结构全方位详解
android·ide·android studio
Sagittarius_A*6 小时前
H3CSE 高性能园区网:园区网安全体系详解
网络·计算机网络·安全·h3cse
__Witheart__6 小时前
Android编译错误:Soong阶段因缺失res目录导致panic (Iwlan模块)
android
酿情师7 小时前
逆向exe文件:CRT 初始化流程详细分析
android·软件构建·逆向·re·crt‘