如何在Android中实现每秒更新的WiFi与移动数据网速监测功能
嘿,这个需求我之前帮朋友做过类似的,其实核心就是实时采集系统的网络流量数据,然后计算每秒的差值得到速度。我给你拆解成几个关键步骤,跟着来就能搞定:
一、先搞定必要的权限
首先得在AndroidManifest.xml里声明需要的权限,因为要读取网络状态和流量数据:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 如果需要后台运行,还要加这个 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
这些都是正常权限,不需要动态申请,直接在Manifest里声明就行。
二、核心逻辑:计算网络速度
Android系统提供了TrafficStats类,专门用来获取网络流量的统计数据。它能分别返回WiFi和移动数据的累计接收/发送字节数。
注意:这些字节数是从设备开机到现在的累计值,所以我们需要每秒记录一次当前值,和上一次的差值就是这1秒内的流量,除以1秒就是速度啦
步骤大概是这样:
- 每秒获取一次WiFi和移动数据的累计流量值
- 和上一秒记录的值做差,得到这1秒的流量消耗
- 把字节数转换成用户友好的单位(KB/s 或 MB/s)
另外,我们还需要判断当前的网络类型,比如用户现在连的是WiFi还是移动数据,这样可以针对性地展示对应的速度,或者提示“未连接”。
三、实时更新UI
要实现每秒更新,我们可以用Handler来做定时任务(或者用协程,看你习惯哪种)。因为更新UI必须在主线程,所以Handler默认绑定主线程的Looper,刚好合适。
每次计算出速度后,直接更新TextView的内容就行,记得把数值格式化成易读的样式,比如保留一位小数,自动切换KB/s和MB/s。
四、完整代码示例
我给你写一个简单的Activity实现,直接就能跑起来:
1. Activity代码(Kotlin)
import android.net.ConnectivityManager import android.net.TrafficStats import android.os.Bundle import android.os.Handler import android.os.Looper import android.widget.TextView import androidx.appcompat.app.AppCompatActivity class SpeedMeterActivity : AppCompatActivity() { private lateinit var wifiSpeedTv: TextView private lateinit var mobileSpeedTv: TextView private val mainHandler = Handler(Looper.getMainLooper()) // 保存上一次的流量累计值 private var lastWifiRxBytes = 0L private var lastMobileRxBytes = 0L override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_speed_meter) wifiSpeedTv = findViewById(R.id.tv_wifi_speed) mobileSpeedTv = findViewById(R.id.tv_mobile_speed) // 启动每秒更新的任务 mainHandler.post(speedUpdateRunnable) } private val speedUpdateRunnable = object : Runnable { override fun run() { calculateAndDisplaySpeed() // 1秒后再次执行 mainHandler.postDelayed(this, 1000) } } private fun calculateAndDisplaySpeed() { val connectivityManager = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager val activeNetwork = connectivityManager.activeNetworkInfo // 获取当前WiFi和移动数据的累计接收字节数 val currentWifiRx = TrafficStats.getWifiRxBytes() val currentMobileRx = TrafficStats.getMobileRxBytes() // 计算并显示WiFi速度 if (currentWifiRx != TrafficStats.UNSUPPORTED && lastWifiRxBytes != 0L) { val speedBytesPerSecond = currentWifiRx - lastWifiRxBytes val speedKbPerSecond = speedBytesPerSecond / 1024.0 val (speed, unit) = if (speedKbPerSecond > 1024) { Pair(speedKbPerSecond / 1024, "MB/s") } else { Pair(speedKbPerSecond, "KB/s") } wifiSpeedTv.text = String.format("WiFi: %.1f %s", speed, unit) } lastWifiRxBytes = currentWifiRx // 计算并显示移动数据速度 if (currentMobileRx != TrafficStats.UNSUPPORTED && lastMobileRxBytes != 0L) { val speedBytesPerSecond = currentMobileRx - lastMobileRxBytes val speedKbPerSecond = speedBytesPerSecond / 1024.0 val (speed, unit) = if (speedKbPerSecond > 1024) { Pair(speedKbPerSecond / 1024, "MB/s") } else { Pair(speedKbPerSecond, "KB/s") } mobileSpeedTv.text = String.format("移动数据: %.1f %s", speed, unit) } lastMobileRxBytes = currentMobileRx // 处理未连接的情况 if (activeNetwork?.type != ConnectivityManager.TYPE_WIFI) { wifiSpeedTv.text = "WiFi: 未连接" } if (activeNetwork?.type != ConnectivityManager.TYPE_MOBILE) { mobileSpeedTv.text = "移动数据: 未连接" } } override fun onDestroy() { super.onDestroy() // 销毁时移除任务,避免内存泄漏 mainHandler.removeCallbacks(speedUpdateRunnable) } }
2. 布局文件(activity_speed_meter.xml)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" android:padding="24dp"> <TextView android:id="@+id/tv_wifi_speed" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="28sp" android:text="WiFi: --"/> <TextView android:id="@+id/tv_mobile_speed" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="28sp" android:layout_marginTop="24dp" android:text="移动数据: --"/> </LinearLayout>
五、一些需要注意的坑
- 兼容性问题:部分老设备可能不支持
TrafficStats,会返回TrafficStats.UNSUPPORTED,所以一定要做判断,避免崩溃。 - 网络状态监听:上面的代码用了
activeNetworkInfo,但这个方法在API 29(Android 10)之后被废弃了。如果要兼容新版本,推荐用ConnectivityManager.NetworkCallback来监听网络状态变化,这样更准确。 - 后台运行:如果需要应用在后台也显示网速,得用前台服务(Foreground Service),否则Android 8以上系统会限制后台进程,导致更新停止。
- 内存泄漏:
Handler如果持有Activity的引用,可能会导致内存泄漏,所以在Activity销毁时一定要移除回调,或者使用WeakHandler。
这样基本就能实现一个每秒更新的网速仪了,如果需要更复杂的功能(比如悬浮窗、历史流量统计),随时说,我再给你补充细节~
内容的提问来源于stack exchange,提问作者Farshan
相关产品推荐
相关产品推荐

