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

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

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

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

Here's the code

foodlistadapter.kt

  1. package com.example.bbar.ui.home
  2. import android.annotation.SuppressLint
  3. import android.view.LayoutInflater
  4. import android.view.View
  5. import android.view.ViewGroup
  6. import androidx.recyclerview.widget.RecyclerView
  7. import com.example.bbar.R
  8. import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
  9. import android.widget.TextView
  10. import com.example.bbar.databinding.FooditemBinding
  11. @SuppressLint("StaticFieldLeak")
  12. private var _binding: FooditemBinding? = null
  13. private val binding get() = _binding!!
  14. class Foodlistadapter(
  15. private val foods: MutableList<food>
  16. ) : RecyclerView.Adapter<Foodlistadapter.foodlistviewholder>() {
  17. class foodlistviewholder(itemView: View) : RecyclerView.ViewHolder(itemView)
  18. override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): foodlistviewholder {
  19. return foodlistviewholder(
  20. LayoutInflater.from(parent.context).inflate(
  21. R.layout.fragment_home,
  22. parent,
  23. false
  24. )
  25. )
  26. }
  27. fun addFood(food: food) {
  28. foods.add(food)
  29. notifyItemInserted(foods.size - 1)
  30. }
  31. fun deleteFood() {
  32. foods.removeAll { foods -> foods.isChecked }
  33. notifyDataSetChanged()
  34. }
  35. private fun toggleStrikeThrough(tvFood: TextView, isChecked: Boolean) {
  36. if (isChecked) {
  37. tvFood.paintFlags = tvFood.paintFlags or STRIKE_THRU_TEXT_FLAG
  38. } else {
  39. tvFood.paintFlags = tvFood.paintFlags or STRIKE_THRU_TEXT_FLAG.inv()
  40. }
  41. }
  42. override fun onBindViewHolder(holder: foodlistviewholder, position: Int) {
  43. val currentFood = foods[position]
  44. holder.itemView.apply {
  45. binding.tvFood.text = currentFood.name
  46. binding.tvCalories.text = currentFood.calories.toString()
  47. binding.cbDelete.isChecked = currentFood.isChecked
  48. toggleStrikeThrough(binding.tvFood, currentFood.isChecked)
  49. binding.cbDelete.setOnCheckedChangeListener { _, isChecked ->
  50. toggleStrikeThrough(binding.tvFood, isChecked)
  51. currentFood.isChecked = !currentFood.isChecked
  52. }
  53. }
  54. }
  55. override fun getItemCount(): Int {
  56. return foods.size
  57. }
  58. }

FragmentHome.kt

  1. package com.example.bbar.ui.home
  2. import android.os.Bundle
  3. import android.view.LayoutInflater
  4. import android.view.View
  5. import android.view.ViewGroup
  6. import androidx.fragment.app.Fragment
  7. import androidx.recyclerview.widget.LinearLayoutManager
  8. import com.example.bbar.R
  9. import com.example.bbar.databinding.FragmentHomeBinding
  10. class HomeFragment : Fragment() {
  11. private var _binding: FragmentHomeBinding? = null
  12. private val binding get() = _binding!!
  13. private lateinit var foodlistadapter: Foodlistadapter
  14. override fun onCreateView(
  15. inflater: LayoutInflater, container: ViewGroup?,
  16. savedInstanceState: Bundle?
  17. ): View {
  18. _binding = FragmentHomeBinding.inflate(inflater, container, false)
  19. return binding.root
  20. }
  21. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  22. super.onViewCreated(view, savedInstanceState)
  23. foodlistadapter = Foodlistadapter(mutableListOf())
  24. binding.rvFoodItems.adapter = foodlistadapter
  25. binding.rvFoodItems.layoutManager = LinearLayoutManager(activity)
  26. binding.bSubmit.setOnClickListener {
  27. val foodTitle = binding.etName.text.toString()
  28. val foodCalories = binding.etCalories.text.toString()
  29. if (foodTitle.isNotEmpty()) {
  30. val food = food(foodTitle, foodCalories.toInt(), false)
  31. foodlistadapter.addFood(food)
  32. binding.etName.text.clear()
  33. binding.etCalories.text.clear()
  34. }
  35. }
  36. binding.bDelete.setOnClickListener {
  37. foodlistadapter.deleteFood()
  38. }
  39. }
  40. override fun onDestroy() {
  41. super.onDestroy()
  42. _binding = null
  43. }
  44. }

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

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

Here's the code

foodlistadapter.kt

  1. package com.example.bbar.ui.home
  2. import android.annotation.SuppressLint
  3. import android.view.LayoutInflater
  4. import android.view.View
  5. import android.view.ViewGroup
  6. import androidx.recyclerview.widget.RecyclerView
  7. import com.example.bbar.R
  8. import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
  9. import android.widget.TextView
  10. import com.example.bbar.databinding.FooditemBinding
  11. @SuppressLint(&quot;StaticFieldLeak&quot;)
  12. private var _binding: FooditemBinding? = null
  13. private val binding get() = _binding!!
  14. class Foodlistadapter(
  15. private val foods: MutableList&lt;food&gt;
  16. ) : RecyclerView.Adapter&lt;Foodlistadapter.foodlistviewholder&gt;() {
  17. class foodlistviewholder(itemView: View) : RecyclerView.ViewHolder(itemView)
  18. override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): foodlistviewholder {
  19. return foodlistviewholder(
  20. LayoutInflater.from(parent.context).inflate(
  21. R.layout.fragment_home,
  22. parent,
  23. false
  24. )
  25. )
  26. }
  27. fun addFood(food: food) {
  28. foods.add(food)
  29. notifyItemInserted(foods.size - 1)
  30. }
  31. fun deleteFood() {
  32. foods.removeAll { foods -&gt; foods.isChecked }
  33. notifyDataSetChanged()
  34. }
  35. private fun toggleStrikeThrough(tvFood: TextView, isChecked: Boolean) {
  36. if (isChecked) {
  37. tvFood.paintFlags = tvFood.paintFlags or STRIKE_THRU_TEXT_FLAG
  38. } else {
  39. tvFood.paintFlags = tvFood.paintFlags or STRIKE_THRU_TEXT_FLAG.inv()
  40. }
  41. }
  42. override fun onBindViewHolder(holder: foodlistviewholder, position: Int) {
  43. val currentFood = foods[position]
  44. holder.itemView.apply {
  45. binding.tvFood.text = currentFood.name
  46. binding.tvCalories.text= currentFood.calories.toString()
  47. binding.cbDelete.isChecked = currentFood.isChecked
  48. toggleStrikeThrough(binding.tvFood, currentFood.isChecked)
  49. binding.cbDelete.setOnCheckedChangeListener { _, isChecked -&gt;
  50. toggleStrikeThrough(binding.tvFood, isChecked)
  51. currentFood.isChecked = !currentFood.isChecked
  52. }
  53. }
  54. }
  55. override fun getItemCount(): Int {
  56. return foods.size
  57. }
  58. }
  1. package com.example.bbar.ui.home
  2. import android.os.Bundle
  3. import android.view.LayoutInflater
  4. import android.view.View
  5. import android.view.ViewGroup
  6. import androidx.fragment.app.Fragment
  7. import androidx.recyclerview.widget.LinearLayoutManager
  8. import com.example.bbar.R
  9. import com.example.bbar.databinding.FragmentHomeBinding
  10. class HomeFragment : Fragment() {
  11. private var _binding: FragmentHomeBinding? = null
  12. private val binding get() = _binding!!
  13. private lateinit var foodlistadapter: Foodlistadapter
  14. override fun onCreateView(
  15. inflater: LayoutInflater, container: ViewGroup?,
  16. savedInstanceState: Bundle?
  17. ): View {
  18. _binding = FragmentHomeBinding.inflate(inflater, container, false)
  19. return binding!!.root
  20. }
  21. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  22. super.onViewCreated(view, savedInstanceState)
  23. foodlistadapter = Foodlistadapter(mutableListOf())
  24. binding.rvFoodItems.adapter = foodlistadapter
  25. binding.rvFoodItems.layoutManager = LinearLayoutManager(activity)
  26. binding.bSubmit.setOnClickListener{
  27. val foodTitle= binding.etName.text.toString()
  28. val foodCalories = binding.etCalories.text.toString()
  29. if (foodTitle.isNotEmpty()){
  30. val food= food(foodTitle, foodCalories.toInt(), false )
  31. foodlistadapter.addFood(food)
  32. binding.etName.text.clear()
  33. binding.etCalories.text.clear()
  34. }
  35. }
  36. binding.bDelete.setOnClickListener{
  37. foodlistadapter.deleteFood()
  38. }
  39. }
  40. override fun onDestroy() {
  41. super.onDestroy()
  42. _binding = null
  43. }
  44. }

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

答案1

得分: 0

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

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

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

将你的 ViewHolder 实现更改为:

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

onCreateViewHolder 中实例化该绑定:

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

onBindViewHolder 中使用绑定:

  1. override fun onBindViewHolder(holder: FoodListViewHolder, position: Int) {
  2. val currentFood = foods[position]
  3. holder.binding.apply {
  4. tvFood.text = currentFood.name
  5. tvCalories.text = currentFood.calories.toString()
  6. cbDelete.isChecked = currentFood.isChecked
  7. toggleStrikeThrough(tvFood, isChecked)
  8. cbDelete.setOnCheckedChangeListener { _, isChecked ->
  9. toggleStrikeThrough(tvFood, isChecked)
  10. currentFood.isChecked = !currentFood.isChecked
  11. }
  12. }
  13. }
英文:

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

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

Change your ViewHolder implementation to:

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

Inflate that binding in onCreateViewHolder:

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

Use the binding in onBindViewHolder:

  1. override fun onBindViewHolder(holder: FoodListViewHolder, position: Int) {
  2. val currentFood = foods[position]
  3. holder.binding.apply {
  4. tvFood.text = currentFood.name
  5. tvCalories.text= currentFood.calories.toString()
  6. cbDelete.isChecked = currentFood.isChecked
  7. toggleStrikeThrough(tvFood, isChecked)
  8. cbDelete.setOnCheckedChangeListener { _, isChecked -&gt;
  9. toggleStrikeThrough(tvFood, isChecked)
  10. currentFood.isChecked = !currentFood.isChecked
  11. }
  12. }
  13. }

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:

确定