Kotlin度量转换APP崩溃排查:when表达式UI显示问题求助
度量转换APP崩溃与when表达式问题排查及修复
问题根源分析
- 重复布局加载:
onCreate中连续调用两次setContentView,第一次加载原始布局,第二次加载ViewBinding根布局,导致布局绑定混乱,易引发空指针或视图异常。 - 无限递归栈溢出:
convertMetric方法最后一行递归调用自身,形成无限循环触发栈溢出,直接导致APP崩溃。 - 错误的条件判断逻辑:用位运算
and组合两个RadioButton的ID,这不是判断“选中A且选中B”的正确方式——位运算会篡改ID数值,导致分支永远匹配不到,出现“分支不可达”提示。 - 未处理非法输入:直接将输入框文本转
Double,若输入为空或非数字,会抛出NumberFormatException导致崩溃。 - 计算结果丢失:每个
when都是独立代码块,计算结果未赋值给变量直接被丢弃,最终无法显示转换结果。
修复步骤及代码修正
1. 修复布局加载问题
移除onCreate中重复的setContentView(R.layout.activity_main),仅保留ViewBinding的布局加载:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // 仅保留这一行 binding.conversionTo.setOnClickListener { convertMetric() } }
2. 消除递归并保存计算结果
将convertMetric改为计算结果后直接赋值,避免递归调用自身:
- 定义变量存储转换结果
- 用
Pair(selectedId, selectedId2)作为when的判断对象,合并所有分支到一个when中
3. 添加输入校验
在转换前判断输入合法性,避免转换异常:
val stringInTextField = binding.howMuchStuffWeTalking.text.toString().trim() if (stringInTextField.isEmpty()) { binding.metricConverted.text = getString(R.string.please_enter_value) return } val amountIQ = try { stringInTextField.toDouble() } catch (e: NumberFormatException) { binding.metricConverted.text = getString(R.string.invalid_input) return }
4. 修正when表达式逻辑
用Pair组合两个选中的RadioButton ID,统一处理所有转换分支,并添加默认分支覆盖未定义的转换组合:
val result = when (Pair(selectedId, selectedId2)) { Pair(R.id.Grain, R.id.Ounce1) -> amountIQ / 437.5 Pair(R.id.Grain, R.id.quarter1) -> amountIQ * 0.000005714 Pair(R.id.Grain, R.id.pound1) -> amountIQ * 0.0001429 Pair(R.id.Grain, R.id.Ton1) -> amountIQ / 1.4e+7 Pair(R.id.Grain, R.id.stone1) -> amountIQ * 0.0000102 else -> { binding.metricConverted.text = getString(R.string.unsupported_conversion) return } } binding.metricConverted.text = getString(R.string.end_result, result)
完整修正代码
package com.example.metricconversion import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.example.metricconversion.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.conversionTo.setOnClickListener { convertMetric() } } fun convertMetric() { val stringInTextField = binding.howMuchStuffWeTalking.text.toString().trim() // 输入校验 if (stringInTextField.isEmpty()) { binding.metricConverted.text = getString(R.string.please_enter_value) return } val amountIQ = try { stringInTextField.toDouble() } catch (e: NumberFormatException) { binding.metricConverted.text = getString(R.string.invalid_input) return } val selectedId = binding.unitThatNeedsToBeConverted.checkedRadioButtonId val selectedId2 = binding.toBeConverted.checkedRadioButtonId // 处理未选中RadioButton的情况 if (selectedId == -1 || selectedId2 == -1) { binding.metricConverted.text = getString(R.string.please_select_units) return } // 统一的when表达式处理转换逻辑 val result = when (Pair(selectedId, selectedId2)) { Pair(R.id.Grain, R.id.Ounce1) -> amountIQ / 437.5 Pair(R.id.Grain, R.id.quarter1) -> amountIQ * 0.000005714 Pair(R.id.Grain, R.id.pound1) -> amountIQ * 0.0001429 Pair(R.id.Grain, R.id.Ton1) -> amountIQ / 1.4e+7 Pair(R.id.Grain, R.id.stone1) -> amountIQ * 0.0000102 else -> { binding.metricConverted.text = getString(R.string.unsupported_conversion) return } } binding.metricConverted.text = getString(R.string.end_result, result) } }
额外优化建议
- 在
strings.xml中添加对应提示字符串(如please_enter_value、invalid_input等),避免硬编码文本 - 为RadioButton组设置默认选中项,减少用户未选中时的提示场景
- 后续扩展其他单位转换时,只需在
when中添加新的Pair分支即可
内容的提问来源于stack exchange,提问作者codingNoob
相关产品推荐
相关产品推荐

