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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 07:09:25