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

Android Kotlin使用TextWatcher.onTextChanged实现加油字段联动触发无限循环问题

解决方案

问题根因

  • 直接在TextWatcher的回调中调用setText()会再次触发TextWatcher回调,形成无限循环
  • 没有对输入值做合法性校验和异常捕获,空输入、非数字输入、除零操作都会触发NumberFormatException
  • 没有适配第三个输入字段fuelCost的监听,也没有判断当前触发变化的字段,无法正确选择计算逻辑方向

修改后实现代码

// 计算锁标志位,避免setText时触发循环回调
var isCalculating = false

val refuelTextWatcher = object : TextWatcher {
    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
    override fun afterTextChanged(s: Editable?) {}
    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        // 正在计算中直接返回,避免循环触发
        if (isCalculating) return

        // 统一封装输入转Float的逻辑,捕获转换异常
        fun getFloatFromInput(text: CharSequence?): Float? {
            return try {
                text?.toString()?.takeIf { it.isNotEmpty() }?.toFloat()
            } catch (e: NumberFormatException) {
                null
            }
        }

        val amount = getFloatFromInput(fuelAmount.text)
        val pricePerUnit = getFloatFromInput(fuelPricePerUnit.text)
        val cost = getFloatFromInput(fuelCost.text)

        isCalculating = true
        try {
            // 场景1:油量和单价都有效,计算总花费
            if (amount != null && amount > 0 && pricePerUnit != null) {
                val finalCost = amount * pricePerUnit
                // 保留2位小数可根据需求调整
                fuelCost.setText("%.2f".format(finalCost))
                // 光标移动到末尾,优化输入体验
                fuelCost.setSelection(fuelCost.text.length)
            }
            // 场景2:油量和总花费都有效,计算单价
            else if (amount != null && amount > 0 && cost != null) {
                val finalPrice = cost / amount
                fuelPricePerUnit.setText("%.2f".format(finalPrice))
                fuelPricePerUnit.setSelection(fuelPricePerUnit.text.length)
            }
        } finally {
            // 计算完成重置标志位
            isCalculating = false
        }
    }
}

// 三个输入框都要添加监听
fuelAmount.addTextChangedListener(refuelTextWatcher)
fuelPricePerUnit.addTextChangedListener(refuelTextWatcher)
fuelCost.addTextChangedListener(refuelTextWatcher)

关键优化说明

  • 新增isCalculating锁标志位,计算过程中拦截TextWatcher的回调,彻底解决无限循环问题
  • 统一封装输入值转Float的逻辑,捕获转换异常,避免非法输入导致崩溃
  • 增加油量大于0的校验,提前拦截除零等非法计算场景
  • 两个计算场景互斥执行,不会出现互相覆盖的问题
  • 数值格式化可选保留小数位数,优化展示效果,同时设置光标位置提升输入体验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 06:27:04