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

Android端CPF校验方法出现ANR问题,求排查原因

导致CPF校验ANR的原因分析

从你提供的代码来看,核心问题出在calculateDigit函数的异常处理逻辑上,会触发无限循环导致主线程阻塞,最终引发ANR:

问题细节

在calculateDigit的while循环中,当Integer.parseInt(str.substring(index, index + 1))抛出NumberFormatException(比如字符串中包含非数字字符)时,catch块里没有执行index--操作。这会导致循环的index值永远停留在当前位置,下一次循环会重复处理同一个字符,再次抛出异常,陷入无限循环。

主线程被这个无限循环占用,无法处理用户交互或系统事件,超过系统阈值后就会触发ANR。

为什么你无法复现?

你测试时可能只用了合法的纯数字CPF,而触发ANR的场景是传入了长度为11但包含非数字字符的字符串(比如带空格、字母或符号的伪CPF),这类输入会触发上述无限循环。

修复方案

修改calculateDigit函数,确保无论是否抛出异常,index都会递减:

private fun calculateDigit(str: String, weightCPF: IntArray): Int {
    var sum = 0
    var index = str.length - 1
    var digit: Int
    while (index >= 0) {
        try {
            digit = Integer.parseInt(str.substring(index, index + 1))
            sum += digit * weightCPF[weightCPF.size - str.length + index]
        } catch (ex: NumberFormatException) {
            Timber.e(ex, "calculateDigit: %s", ex.message)
            // 遇到非法字符直接返回无效标记,让上层判断校验不通过
            return -1
        } finally {
            index-- // 无论是否异常,都要递减index,避免无限循环
        }
    }
    sum = 11 - sum % 11
    return if (sum > 9) 0 else sum
}

另外,也可以在isValidCPF的开头先校验字符串是否为纯数字,提前拦截非法输入:

fun isValidCPF(cpf: String?): Boolean {
    if (cpf == null || cpf.length != 11) return false
    val trimmedCpf = cpf.trim { it <= ' ' }
    if (trimmedCpf == "00000000000" || !trimmedCpf.all { it.isDigit() }) {
        return false
    }
    val digit1 = calculateDigit(trimmedCpf.substring(0, 9), weightCPF)
    val digit2 = calculateDigit(trimmedCpf.substring(0, 9) + digit1, weightCPF)
    return trimmedCpf == trimmedCpf.substring(0, 9) + digit1.toString() + digit2.toString()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 09:01:08