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

Kotlin安卓APP点击添加按钮崩溃,抛出NullPointerException

解决RecyclerView Adapter空指针崩溃问题

崩溃日志

FATAL EXCEPTION: main
Process: com.example.bbar, PID: 25930
java.lang.NullPointerException
at com.example.bbar.ui.home.FoodlistadapterKt.getBinding(foodlistadapter.kt:16)
at com.example.bbar.ui.home.FoodlistadapterKt.access$getBinding(foodlistadapter.kt:1)
at com.example.bbar.ui.home.Foodlistadapter.onBindViewHolder(foodlistadapter.kt:57)
at com.example.bbar.ui.home.Foodlistadapter.onBindViewHolder(foodlistadapter.kt:18)

问题根源

  1. 全局静态Binding未初始化:你在Foodlistadapter中定义了全局静态的FooditemBinding变量,但从未对其赋值,调用binding!!时直接触发空指针。
  2. 加载错误布局:onCreateViewHolder中加载了fragment_home布局,而非RecyclerView Item对应的fooditem布局,导致无法找到item内的控件。
  3. ViewHolder未持有独立Binding:没有让每个ViewHolder持有对应item的Binding实例,错误依赖全局未初始化的Binding。

修复后的完整foodlistadapter.kt代码

package com.example.bbar.ui.home

import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.bbar.databinding.FooditemBinding

class Foodlistadapter(
    private val foods: MutableList<food>
) : RecyclerView.Adapter<Foodlistadapter.FoodlistViewHolder>() {

    // ViewHolder持有当前item的Binding实例
    inner class FoodlistViewHolder(val binding: FooditemBinding) : RecyclerView.ViewHolder(binding.root)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FoodlistViewHolder {
        // 加载正确的Item布局
        val binding = FooditemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return FoodlistViewHolder(binding)
    }

    fun addFood(food: food) {
        foods.add(food)
        notifyItemInserted(foods.size - 1)
    }

    fun deleteFood() {
        foods.removeAll { it.isChecked }
        notifyDataSetChanged()
    }

    private fun toggleStrikeThrough(textView: android.widget.TextView, isChecked: Boolean) {
        textView.paintFlags = if (isChecked) {
            textView.paintFlags or STRIKE_THRU_TEXT_FLAG
        } else {
            textView.paintFlags and STRIKE_THRU_TEXT_FLAG.inv()
        }
    }

    override fun onBindViewHolder(holder: FoodlistViewHolder, position: Int) {
        val currentFood = foods[position]
        holder.binding.apply {
            tvFood.text = currentFood.name
            tvCalories.text = currentFood.calories.toString()
            cbDelete.isChecked = currentFood.isChecked
            toggleStrikeThrough(tvFood, currentFood.isChecked)

            cbDelete.setOnCheckedChangeListener { _, isChecked ->
                toggleStrikeThrough(tvFood, isChecked)
                currentFood.isChecked = isChecked
            }
        }
    }

    override fun getItemCount(): Int = foods.size
}

关键修改点

  • 移除全局静态Binding变量,改为让每个FoodlistViewHolder持有对应item的Binding实例,确保每个item有独立的控件引用。
  • onCreateViewHolder中使用FooditemBinding.inflate()加载正确的item布局,替代原错误的fragment_home布局。
  • onBindViewHolder中通过holder.binding访问当前item的控件,彻底避免空指针。
  • 修正deleteFood中的变量名冲突(原代码参数名与类成员变量重名)。
  • 修正复选框状态同步逻辑,直接将isChecked赋值给currentFood.isChecked,避免逻辑错误。

额外优化建议

在HomeFragment的提交按钮点击事件中,未判断热量输入是否为有效数字,可能触发NumberFormatException,建议添加校验:

binding.bSubmit.setOnClickListener{
    val foodTitle= binding.etName.text.toString().trim()
    val foodCaloriesStr = binding.etCalories.text.toString().trim()
    if (foodTitle.isNotEmpty() && foodCaloriesStr.isNotEmpty()){
        try {
            val foodCalories = foodCaloriesStr.toInt()
            val food= food(foodTitle, foodCalories, false )
            foodlistadapter.addFood(food)
            binding.etName.text.clear()
            binding.etCalories.text.clear()
        } catch (e: NumberFormatException) {
            // 可在此提示用户输入有效的数字
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 14:14:54