Android获取动态View中EditText值计算GPA报NumberFormatException
GPA计算触发
NumberFormatException: For input string: "null"修复方案 报错核心原因是调用数字转换方法时传入的字符串内容为"null",不属于合法数字格式,常见触发场景共3种:
- 查找EditText时id写错、或者查找范围不对,
findViewById返回空对象,直接调用text.toString()得到的就是字符串"null",不是输入框实际内容 - 遍历
layout_list子View时,把容器内非动态添加的其他控件(比如Add按钮、提示文案、分割线)也当成课程条目布局取EditText,拿不到目标控件 - 输入框为空时未做判空处理,部分场景下取到的输入内容为null,转字符串后直接变成"null"传入数字转换方法
修复步骤
1. 修正遍历与计算逻辑,增加合法性校验
遍历容器时先过滤非课程条目的子View,所有输入值先做判空、格式校验再参与计算,避免非法值触发崩溃:
fun calculate() { val container = findViewById<LinearLayout>(R.id.layout_list) var totalWeightedPoint = 0.0 var totalCredit = 0.0 for (i in 0 until container.childCount) { val childView = container.getChildAt(i) // 跳过非课程条目的其他子View if (childView.tag != "course_item") continue // 从当前条目范围内找输入框,不要直接在Activity层面找控件 val gpaEt = childView.findViewById<EditText>(R.id.gpa_points) val creditEt = childView.findViewById<EditText>(R.id.credit_points) // 取出输入内容并去掉首尾空格 val gpaStr = gpaEt.text?.toString()?.trim() val creditStr = creditEt.text?.toString()?.trim() // 空值直接拦截,不要进入转换逻辑 if (gpaStr.isNullOrEmpty() || creditStr.isNullOrEmpty()) { Toast.makeText(this, "请填写完整所有课程的绩点和学分", Toast.LENGTH_SHORT).show() return } // 捕获数字转换异常,拦截非数字输入 runCatching { val gpa = gpaStr.toDouble() val credit = creditStr.toDouble() // 校验数值范围合法性 if (gpa < 0 || gpa > 5 || credit <= 0) { Toast.makeText(this, "绩点/学分输入值不合法", Toast.LENGTH_SHORT).show() return } totalWeightedPoint += gpa * credit totalCredit += credit }.onFailure { Toast.makeText(this, "请输入合法的数字内容", Toast.LENGTH_SHORT).show() return } } // 拦截学分为0的场景,避免除零异常 if (totalCredit == 0.0) { Toast.makeText(this, "请先添加课程并填写学分", Toast.LENGTH_SHORT).show() return } val finalGpa = totalWeightedPoint / totalCredit // 此处写最终GPA的展示逻辑即可 }
2. 调整动态加载的条目布局配置
给new_layout.xml的根布局加tag标记,方便遍历时识别条目,同时给输入框设置数字输入类型,减少非法输入:
<!-- new_layout根布局示例 --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:tag="course_item" android:orientation="horizontal" android:padding="12dp"> <EditText android:id="@+id/gpa_points" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:inputType="numberDecimal" android:hint="输入课程绩点"/> <EditText android:id="@+id/credit_points" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:inputType="numberDecimal" android:hint="输入课程学分"/> </LinearLayout>
3. 检查Add按钮的动态加载逻辑
确认点击Add按钮时布局加载、添加逻辑无id写错的问题:
findViewById<Button>(R.id.add_btn).setOnClickListener { val courseItem = LayoutInflater.from(this).inflate(R.layout.new_layout, null) val container = findViewById<LinearLayout>(R.id.layout_list) container.addView(courseItem) }
避坑提醒
- 不要直接在Activity层面调用
findViewById(R.id.gpa_points)获取动态添加的输入框:多个动态条目的控件id重复,这种写法只会拿到第一个匹配的控件,遍历条目时必须从当前条目的子View范围内查找目标EditText - 所有字符串转数字的逻辑必须加判空和异常捕获:用户输入空值、特殊字符是常态,不能默认用户一定会输入合法数字
- 如果
layout_list内除了动态添加的课程条目,还放了计算按钮、标题这类固定控件,要么把这类固定控件移到layout_list容器外面,要么就用上面提到的tag标记方式跳过非条目View,否则取控件时必然返回null
内容的提问来源于stack exchange,提问作者jane
相关产品推荐
相关产品推荐

