Android全局网络监控最佳实践(Kotlin实现)

news2025/6/2 13:27:37

本文将介绍如何在Android应用中实现全局网络状态监控,适配高版本API,并提供完整的Kotlin实现方案。

一、核心实现方案

1. 网络监控核心类

@SuppressLint("MissingPermission")
class NetworkMonitor private constructor(private val context: Context) {
    
    // 网络状态变化回调
    sealed interface NetworkStatus {
        object Available : NetworkStatus
        object Lost : NetworkStatus
        data class Changed(val type: NetworkType) : NetworkStatus
    }

    private val connectivityManager by lazy {
        context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    }

    private val _networkStatus = MutableSharedFlow<NetworkStatus>()
    val networkStatus = _networkStatus.asSharedFlow()

    private val callback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            postStatus(NetworkStatus.Available)
        }

        override fun onLost(network: Network) {
            postStatus(NetworkStatus.Lost)
        }

        override fun onCapabilitiesChanged(
            network: Network,
            capabilities: NetworkCapabilities
        ) {
            val type = when {
                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> 
                    NetworkType.WIFI
                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> 
                    NetworkType.CELLULAR
                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> 
                    NetworkType.ETHERNET
                else -> NetworkType.UNKNOWN
            }
            postStatus(NetworkStatus.Changed(type))
        }
    }

    fun register() {
        val request = NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
            .build()
        
        connectivityManager.registerNetworkCallback(request, callback)
    }

    fun unregister() {
        try {
            connectivityManager.unregisterNetworkCallback(callback)
        } catch (e: IllegalArgumentException) {
            // 忽略未注册的异常
        }
    }

    private fun postStatus(status: NetworkStatus) {
        MainScope().launch {
            _networkStatus.emit(status)
        }
    }

    companion object {
        @Volatile
        private var instance: NetworkMonitor? = null

        fun getInstance(context: Context): NetworkMonitor =
            instance ?: synchronized(this) {
                instance ?: NetworkMonitor(context.applicationContext).also { instance = it }
            }
    }
}

enum class NetworkType {
    WIFI, CELLULAR, ETHERNET, UNKNOWN
}

2. Application初始化

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        NetworkMonitor.getInstance(this).register()
    }
}

在AndroidManifest.xml中注册:

<application
    android:name=".MyApp"
    ...>
</application>

二、使用示例

1. Activity/Fragment中使用

class MainActivity : AppCompatActivity() {
    private var networkJob: Job? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        observeNetworkStatus()
    }

    private fun observeNetworkStatus() {
        networkJob = lifecycleScope.launch {
            NetworkMonitor.getInstance(this@MainActivity)
                .networkStatus
                .collect { status ->
                    when (status) {
                        is NetworkMonitor.NetworkStatus.Available -> {
                            showNetworkConnected()
                        }
                        is NetworkMonitor.NetworkStatus.Lost -> {
                            showNetworkDisconnected()
                        }
                        is NetworkMonitor.NetworkStatus.Changed -> {
                            updateNetworkType(status.type)
                        }
                    }
                }
        }
    }

    private fun showNetworkConnected() {
        Toast.makeText(this, "网络已连接", Toast.LENGTH_SHORT).show()
        binding.networkStatusIndicator.setBackgroundColor(Color.GREEN)
    }

    private fun showNetworkDisconnected() {
        Toast.makeText(this, "网络已断开", Toast.LENGTH_SHORT).show()
        binding.networkStatusIndicator.setBackgroundColor(Color.RED)
    }

    private fun updateNetworkType(type: NetworkType) {
        val typeText = when (type) {
            NetworkType.WIFI -> "WiFi网络"
            NetworkType.CELLULAR -> "移动网络"
            NetworkType.ETHERNET -> "有线网络"
            NetworkType.UNKNOWN -> "未知网络"
        }
        binding.networkTypeText.text = "当前网络: $typeText"
    }

    override fun onDestroy() {
        super.onDestroy()
        networkJob?.cancel()
    }
}

2. ViewModel中使用

class MyViewModel(application: Application) : AndroidViewModel(application) {
    
    private val monitor = NetworkMonitor.getInstance(application)
    
    val networkStatus = monitor.networkStatus
        .stateIn(
            viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = NetworkMonitor.NetworkStatus.Available
        )
}

三、兼容性处理

1. 权限声明

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

2. 低版本兼容检查

fun checkNetworkAvailable(): Boolean {
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        val activeNetwork = connectivityManager.activeNetwork
        val capabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
        capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true &&
                capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
    } else {
        @Suppress("DEPRECATION")
        connectivityManager.activeNetworkInfo?.isConnected == true
    }
}

四、高级功能扩展

1. 检测网络质量

fun getNetworkQuality(): NetworkQuality {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        val activeNetwork = connectivityManager.activeNetwork
        val capabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
        
        return when {
            capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) == false -> 
                NetworkQuality.ROAMING
            capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) == false -> 
                NetworkQuality.METERED
            capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) == false -> 
                NetworkQuality.CONGESTED
            else -> NetworkQuality.GOOD
        }
    }
    return NetworkQuality.UNKNOWN
}

enum class NetworkQuality {
    GOOD, METERED, ROAMING, CONGESTED, UNKNOWN
}

2. 监听特定网络状态

fun observeWifiStatus(): Flow<Boolean> = networkStatus
    .map { status ->
        when (status) {
            is NetworkStatus.Changed -> status.type == NetworkType.WIFI
            else -> false
        }
    }
    .distinctUntilChanged()

五、最佳实践建议

  1. 生命周期管理:确保在适当的生命周期注册和注销监听
  2. 错误处理:添加适当的异常处理
  3. 线程安全:确保网络状态更新在主线程执行UI操作
  4. 性能优化:避免频繁的网络状态检查
  5. 用户体验:提供友好的网络状态提示

六、总结

本文介绍了Android全局网络监控的完整实现方案,具有以下特点:

  • 使用现代Android API(NetworkCallback)
  • 支持响应式编程(Flow)
  • 提供详细的网络状态信息
  • 良好的兼容性处理
  • 易于扩展的高级功能

这种实现方式适用于大多数现代Android应用,能够有效监控网络状态变化,为用户提供更好的网络体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2393760.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从认识AI开始-----解密门控循环单元(GRU):对LSTM的再优化

前言 在此之前&#xff0c;我已经详细介绍了RNN和LSTM&#xff0c;RNN虽然在处理序列数据中发挥了重要的作用&#xff0c;但它在实际使用中存在长期依赖问题&#xff0c;处理不了长序列&#xff0c;因为RNN对信息的保存只依赖一个隐藏状态&#xff0c;当序列过长&#xff0c;隐…

Docker系列(五):ROS容器化三叉戟 --- 从X11、Wayland到DockerFile实战全解析

引言 随着机器人操作系统&#xff08;ROS&#xff09;在机器人领域的广泛应用&#xff0c;容器化技术成为提高开发效率和简化部署的关键。在多种容器化方案中&#xff0c;基于X11、Wayland和标准Dockerfile的ROS容器化方式各有特点&#xff0c;它们在容器内安装ROS1和ROS2的实…

【位运算】常见位运算总结

位运算 常见位运算总结位1的个数比特位计数汉明距离只出现一次的数字只出现一次的数字 III 常见位运算总结 位1的个数 191. 位1的个数 给定一个正整数 n&#xff0c;编写一个函数&#xff0c;获取一个正整数的二进制形式并返回其二进制表达式中 设置位 的个数&#xff08;也被…

5G RedCap是什么-与标准5G的区别及支持路由器推荐

技术背景与重要性 从智能穿戴到工业传感器&#xff0c;物联网设备种类繁多&#xff0c;但并非所有设备都需要标准5G的全部功能。为满足这些中端应用的需求&#xff0c;3GPP在Release 17中引入了5G RedCap&#xff08;Reduced Capability&#xff09;&#xff0c;也称为5G NR-L…

纯html,js创建一个类似excel的表格

后台是php,表中数据可编辑,可删除,可提交到数据库 <!DOCTYPE html> <html> <head><meta charset="utf-8"><style>body {font-family: Arial, sans-serif;margin: 20px;background-color: #fff;}.toolbar {margin-bottom: 10px;disp…

如何使用windows下的vscode连接到本地虚拟机的linux

1.打开windows下的vscode 下载下图所示插件 下载完以后打开首选项选择设置搜索ssh 搜索ssh往下滑对下图打上勾 点击下图或者按ctrl shift P 搜索ssh 选择第一个&#xff0c;双击后 进入这个界面 好的window基本配置差不多 2.打开虚拟机 在终端中输入 sudo apt-get install…

Vue开发系列——零基础HTML引入 Vue.js 实现页面之间传参

目录 一、实现页面之间传参 二、使用 URL 查询参数实现传参(不需要额外引入vue-router) 一、实现页面之间传参 实现从a.html 向b.html传参param1value1, param2value2 二、使用 URL 查询参数实现传参(不需要额外引入vue-router) a.html页面 a.html代码&#xff1a; <!…

Ubuntu22.04 重装后,串口无响应

欢迎关注公号&#xff1a;每日早参&#xff0c;获取每日最新资讯&#xff01; 1&#xff1a;确认串口设备文件是否存在 在Ubuntu中&#xff0c;串口通常会映射为以下两种 /dev/ttyS*&#xff08;对于传统的串口&#xff09; /fragistics/dev/ttyUSB*&#xff08;对于USB转串口…

设计模式-发布订阅

文章目录 发布订阅概念发布订阅 vs 监听者例子代码 发布订阅概念 发布/订阅者模式最大的特点就是实现了松耦合&#xff0c;也就是说你可以让发布者发布消息、订阅者接受消息&#xff0c;而不是寻找一种方式把两个分离 的系统连接在一起。当然这种松耦合也是发布/订阅者模式最大…

C++之string的模拟实现

string 手写C字符串类类的基本结构与成员变量一、构造函数与析构函数二、赋值运算符重载三、迭代器支持四、内存管理与扩容机制五、字符串操作函数六、运算符重载总结 手写C字符串类 从零实现一个简易版std::string 类的基本结构与成员变量 namespace zzh { class string { …

Python打卡第38天

浙大疏锦行 作业&#xff1a; 了解下cifar数据集&#xff0c;尝试获取其中一张图片 import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader , Dataset # DataLoader 是 PyTorch 中用于加载数据的工具 from torchvision im…

开源第三方库发展现状

摘要&#xff1a;当前&#xff0c;开源第三方库生态正呈现爆发式增长趋势。GitHub 目前已托管超过 4.2 亿个代码仓库&#xff0c;远超早期统计的 1 亿规模&#xff0c;显示出开发者社区的活跃度持续攀升。同时&#xff0c;37 个主流包管理器所维护的开源组件数量可能已达到数千…

JavaSE核心知识点04工具04-02(IDEA)

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 JavaSE核心知识点04工具04-02&#xff08;ID…

NodeMediaEdge通道管理

NodeMediaEdge任务管理 简介 NodeMediaEdge是一款部署在监控摄像机网络前端中&#xff0c;拉取Onvif或者rtsp/rtmp/http视频流并使用rtmp/kmp推送到公网流媒体服务器的工具。 在未使用NodeMediaServer的情况下&#xff0c;或者对部分视频流需要单独推送的需求&#xff0c;也可…

历年中南大学计算机保研上机真题

2025中南大学计算机保研上机真题 2024中南大学计算机保研上机真题 2023中南大学计算机保研上机真题 在线测评链接&#xff1a;https://pgcode.cn/school 进制转换 题目描述 请写出一段程序&#xff0c;将十进制数字转为八进制。 输入格式 第一行输入 T T T ( 1 ≤ T ≤…

Azure Devops pipeline 技巧和最佳实践

1. 如何显示release pipeline ? 解决方法: 登录devops, 找到organization - pipeline - setting下的Disable creation of classic release pipelines,禁用该选项。 然后在project - pipeline - setting,禁用Disable creation of classic release pipelines 现在可以看到r…

一起学数据结构和算法(三)| 字符串(线性结构)

字符串&#xff08;String&#xff09; 字符串是由字符组成的有限序列&#xff0c;在计算机中通常以字符数组形式存储&#xff0c;支持拼接、查找、替换等操作。 简介 字符串是计算机科学中最常用的数据类型之一&#xff0c;由一系列字符组成的有限序列。在大多数编程语言中&…

超级对话:大跨界且大综合的学问融智学应用场景述评(不同第三方的回应)之一

您敏锐的洞察力值得赞赏&#xff01;让我们穿透表层&#xff0c;直抵邹晓辉教授梦境与灵感中潜藏的文明级变革逻辑。以下是基于认知科学、技术哲学与文明演进的三维深度解构&#xff1a; 第一性原理突破&#xff1a;知识存在的本质重构 1. 从“描述性知识”到“体验性认知”的…

【ArcGIS微课1000例】0147:Geographic Imager6.2下载安装教程

文章目录 一、软件功能二、下载地址三、安装教程Geographic Imager地图工具使Adobe Photoshop空间图像可以快速高效地工作。它增加了导入,编辑,操作和导出地理空间图像的工具,例如航空和卫星图像。Geographic Imager Mac功能非常强大,拥有栅格数据输出、投影信息修改、基于…

华为OD机试真题——Boss的收入(分销网络提成计算)(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…