You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin实现类系统信号塔样式的网络信号强度计算与展示

Android Kotlin 实现对齐系统规则的移动网络信号强度展示方案

前置权限配置

首先在AndroidManifest.xml中添加必要权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Android 12+ 获取蜂窝信号强度强制要求该权限,否则返回无效值 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Android 9及以下版本兼容权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Android 6.0(API 23)及以上版本需要在页面运行时动态申请ACCESS_FINE_LOCATION权限,用户授权后才能正常获取信号数据,未授权状态下所有信号接口返回默认无效值。

核心信号监听实现

Android 10(API 29)及以上推荐使用TelephonyCallback实现信号监听,低版本兼容旧版PhoneStateListener即可,信号计算逻辑完全复用。
信号格数判定完全对齐AOSP原生规则,共分5档(0~4格,0格为无信号,4格为满格),不同网络制式的判定阈值如下:

  • 2G(GSM):基于RSSI值(单位dBm)
    • ≤-105dBm:0格
    • -104~-99dBm:1格
    • -98~-93dBm:2格
    • -92~-85dBm:3格
    • ≥-84dBm:4格
  • 4G(LTE):基于RSRP值(单位dBm)
    • ≤-125dBm:0格
    • -124~-115dBm:1格
    • -114~-105dBm:2格
    • -104~-95dBm:3格
    • ≥-94dBm:4格
  • 5G(NR):基于SSRSRP值(单位dBm)
    • ≤-120dBm:0格
    • -119~-110dBm:1格
    • -109~-100dBm:2格
    • -99~-90dBm:3格
    • ≥-89dBm:4格

核心实现代码如下:

private lateinit var telephonyManager: TelephonyManager
private var signalCallback: TelephonyCallback? = null

// 在页面onStart生命周期中启动监听
@RequiresApi(Build.VERSION_CODES.S)
fun startSignalMonitor() {
    telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
    signalCallback = object : TelephonyCallback(), TelephonyCallback.SignalStrengthsListener {
        override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
            val currentLevel = getMatchSystemSignalLevel(signalStrength)
            // 拿到格数后直接更新UI即可
            refreshSignalUi(currentLevel, signalStrength)
        }
    }
    telephonyManager.registerTelephonyCallback(mainExecutor, signalCallback!!)
}

// 优先复用系统计算结果,保证和状态栏显示一致,兜底逻辑适配异常ROM
private fun getMatchSystemSignalLevel(signalStrength: SignalStrength): Int {
    val systemCalcLevel = signalStrength.level
    if (systemCalcLevel in 0..4) return systemCalcLevel

    // 系统返回无效值时用自定义阈值兜底
    var targetLevel = 0
    signalStrength.cellSignalStrengths.forEach { cellInfo ->
        val dbmValue = cellInfo.dbm
        targetLevel = when {
            cellInfo.javaClass.name.contains("GsmSignalStrength") -> calcGsmLevel(dbmValue)
            cellInfo.javaClass.name.contains("LteSignalStrength") -> calcLteLevel(dbmValue)
            cellInfo.javaClass.name.contains("NrSignalStrength") -> calcNrLevel(dbmValue)
            else -> cellInfo.level
        }
    }
    return targetLevel.coerceIn(0, 4)
}

// 各制式兜底格数计算
private fun calcGsmLevel(dbm: Int): Int = when {
    dbm >= -84 -> 4
    dbm >= -92 -> 3
    dbm >= -98 -> 2
    dbm >= -104 -> 1
    else -> 0
}

private fun calcLteLevel(dbm: Int): Int = when {
    dbm >= -94 -> 4
    dbm >= -104 -> 3
    dbm >= -114 -> 2
    dbm >= -124 -> 1
    else -> 0
}

private fun calcNrLevel(dbm: Int): Int = when {
    dbm >= -89 -> 4
    dbm >= -99 -> 3
    dbm >= -109 -> 2
    dbm >= -119 -> 1
    else -> 0
}

// 页面onStop生命周期中注销监听,避免内存泄漏
fun stopSignalMonitor() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        signalCallback?.let { telephonyManager.unregisterTelephonyCallback(it) }
    }
}

UI适配说明

  • 图标资源可直接复用系统内置的信号塔素材,也可自行准备04格对应状态的切图:0格展示带断开标识的无信号图标,14格分别展示对应格数的信号塔图标即可,和系统状态栏逻辑完全一致。
  • 信号数值展示直接取当前驻网小区的dbm值即可,单位为dBm,注意该值为负数,绝对值越小代表信号质量越好,不要转成正数展示造成用户误解。
  • 双卡场景下需要监听指定SIM卡信号时,调用telephonyManager.createForSubscriptionId(对应卡的subId)生成指定卡的TelephonyManager实例即可,后续逻辑和单卡完全一致。

避坑提示

  • 不要调用WifiManager相关的信号获取接口,该接口仅能获取WiFi信号强度,和蜂窝移动网络无关。
  • Android 9及以下版本无法使用TelephonyCallback时,替换为旧版PhoneStateListener的LISTEN_SIGNAL_STRENGTHS回调即可,信号计算逻辑不需要修改。
  • 优先使用系统自带的SignalStrength.getLevel()返回值,不要全量走自定义阈值计算——部分国产定制ROM会调整信号格数的判定规则,直接用系统计算结果能保证App内显示的格数和系统状态栏完全对齐,不会出现显示不一致的问题。

内容的提问来源于stack exchange,提问作者UserSynergy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 06:45:47