Kotlin应用程序在按钮按下后崩溃,出现NullPointerException。

huangapple go评论89阅读模式
英文:

Kotlin app crashes after button press with NullPointerException

问题

I am making a Kotlin app in Android Studio where I can add foods with their calorie values like a list.

How it is supposed to work is that the two EditText components, "etName" and "etCalories," would be passed into a list, then the TextView inside the RecyclerView should show them.

The issue is, if I press the button to add the item, the app crashes.

Here's the logcat

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)

Here's the code

foodlistadapter.kt

package com.example.bbar.ui.home

import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.bbar.R
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.widget.TextView
import com.example.bbar.databinding.FooditemBinding

@SuppressLint("StaticFieldLeak")
private var _binding: FooditemBinding? = null
private val binding get() =  _binding!!

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

    class foodlistviewholder(itemView: View) : RecyclerView.ViewHolder(itemView)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): foodlistviewholder {
        return foodlistviewholder(
            LayoutInflater.from(parent.context).inflate(
                R.layout.fragment_home,
                parent,
                false
            )
        )
    }

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

    fun deleteFood() {
        foods.removeAll { foods -> foods.isChecked }
        notifyDataSetChanged()
    }

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

    override fun onBindViewHolder(holder: foodlistviewholder, position: Int) {
        val currentFood = foods[position]
        holder.itemView.apply {
            binding.tvFood.text = currentFood.name
            binding.tvCalories.text = currentFood.calories.toString()
            binding.cbDelete.isChecked = currentFood.isChecked
            toggleStrikeThrough(binding.tvFood, currentFood.isChecked)
            binding.cbDelete.setOnCheckedChangeListener { _, isChecked ->
                toggleStrikeThrough(binding.tvFood, isChecked)
                currentFood.isChecked = !currentFood.isChecked
            }
        }
    }

    override fun getItemCount(): Int {
        return foods.size
    }
}

FragmentHome.kt

package com.example.bbar.ui.home

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.bbar.R
import com.example.bbar.databinding.FragmentHomeBinding

class HomeFragment : Fragment() {

    private var _binding: FragmentHomeBinding? = null
    private val binding get() = _binding!!

    private lateinit var foodlistadapter: Foodlistadapter

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentHomeBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        foodlistadapter = Foodlistadapter(mutableListOf())
        binding.rvFoodItems.adapter = foodlistadapter
        binding.rvFoodItems.layoutManager = LinearLayoutManager(activity)

        binding.bSubmit.setOnClickListener {
            val foodTitle = binding.etName.text.toString()
            val foodCalories = binding.etCalories.text.toString()
            if (foodTitle.isNotEmpty()) {
                val food = food(foodTitle, foodCalories.toInt(), false)
                foodlistadapter.addFood(food)
                binding.etName.text.clear()
                binding.etCalories.text.clear()
            }
        }
        binding.bDelete.setOnClickListener {
            foodlistadapter.deleteFood()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }
}

Summary: Tried to add food with its respected calorie value with a button, but the program crashes.

英文:

I am making a Kotlin app in Android Studio where I can add foods with their calorie values like a list.

How it is supposed to work is that the two EditText components, "etName" and "etCalories", would be passed into a list, then the TextView inside the RecyclerView should show them.

The issue is, if I press the button to add the item, the app crashes.

Here's the logcat

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)

Here's the code

foodlistadapter.kt

package com.example.bbar.ui.home

import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.bbar.R
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.widget.TextView
import com.example.bbar.databinding.FooditemBinding


@SuppressLint(&quot;StaticFieldLeak&quot;)
private var _binding: FooditemBinding? = null
private val binding get() =  _binding!!

class Foodlistadapter(

    private val foods: MutableList&lt;food&gt;
) : RecyclerView.Adapter&lt;Foodlistadapter.foodlistviewholder&gt;() {

    class foodlistviewholder(itemView: View) : RecyclerView.ViewHolder(itemView)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): foodlistviewholder {
        return foodlistviewholder(
            LayoutInflater.from(parent.context).inflate(
                R.layout.fragment_home,
                parent,
                false
            )
        )
    }

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

     fun deleteFood() {
        foods.removeAll { foods -&gt; foods.isChecked }
        notifyDataSetChanged()

    }

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

    override fun onBindViewHolder(holder: foodlistviewholder, position: Int) {
        val currentFood = foods[position]
        holder.itemView.apply {
            binding.tvFood.text = currentFood.name
            binding.tvCalories.text= currentFood.calories.toString()
            binding.cbDelete.isChecked = currentFood.isChecked
            toggleStrikeThrough(binding.tvFood, currentFood.isChecked)
            binding.cbDelete.setOnCheckedChangeListener { _, isChecked -&gt;
                toggleStrikeThrough(binding.tvFood, isChecked)
                currentFood.isChecked = !currentFood.isChecked
            }
        }
    }

    override fun getItemCount(): Int {
        return foods.size
    }
}
package com.example.bbar.ui.home

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.bbar.R

import com.example.bbar.databinding.FragmentHomeBinding



class HomeFragment : Fragment() {

    private var _binding: FragmentHomeBinding? = null
    private val binding get() = _binding!!

    private lateinit var foodlistadapter: Foodlistadapter

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentHomeBinding.inflate(inflater, container, false)

        return binding!!.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        foodlistadapter = Foodlistadapter(mutableListOf())
        binding.rvFoodItems.adapter = foodlistadapter
        binding.rvFoodItems.layoutManager = LinearLayoutManager(activity)

        binding.bSubmit.setOnClickListener{
            val foodTitle= binding.etName.text.toString()
            val foodCalories = binding.etCalories.text.toString()
            if (foodTitle.isNotEmpty()){
                val food= food(foodTitle, foodCalories.toInt(), false )
                foodlistadapter.addFood(food)
                binding.etName.text.clear()
                binding.etCalories.text.clear()
            }
        }
        binding.bDelete.setOnClickListener{
            foodlistadapter.deleteFood()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }
}

Summary: Tried to add food with its respected calorie value with a button, but program crashes.

答案1

得分: 0

你的 binding 为空,而且没有被正确使用。

首先,将声明移到类外部,即:

@SuppressLint("StaticFieldLeak")
private var _binding: FooditemBinding? = null
private val binding get() = _binding!!

将你的 ViewHolder 实现更改为:

class FoodListViewHolder(val binding: FooditemBinding) : RecyclerView.ViewHolder(binding.root)

onCreateViewHolder 中实例化该绑定:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FoodListViewHolder {
    val inflater = LayoutInflater.from(parent.context)
    return FoodListViewHolder(FooditemBinding.inflate(inflater, parent, false))
}

onBindViewHolder 中使用绑定:

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, isChecked)
        cbDelete.setOnCheckedChangeListener { _, isChecked ->
            toggleStrikeThrough(tvFood, isChecked)
            currentFood.isChecked = !currentFood.isChecked
        }
    }
}
英文:

You binding is null & also it isn't used correctly.
First of, remove the declaration outside the class i.e:

@SuppressLint(&quot;StaticFieldLeak&quot;)
private var _binding: FooditemBinding? = null
private val binding get() =  _binding!!

Change your ViewHolder implementation to:

class FoodListViewHolder(val binding: FooditemBinding) : RecyclerView.ViewHolder(binding.root)

Inflate that binding in onCreateViewHolder:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FoodListViewHolder {
    val inflater = LayoutInflater.from(parent.context)
    return FoodListViewHolder(FooditemBinding.inflate(inflater, parent, false))
}

Use the binding in onBindViewHolder:

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, isChecked)
        cbDelete.setOnCheckedChangeListener { _, isChecked -&gt;
            toggleStrikeThrough(tvFood, isChecked)
            currentFood.isChecked = !currentFood.isChecked
        }
    }
}

huangapple
  • 本文由 发表于 2023年6月19日 00:01:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76501415.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定