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
相关产品推荐
相关产品推荐

