Проблема с автоматическим обновлением RecycleView (Kotlin)

#android #kotlin #android-fragments #android-recyclerview

#Android #kotlin #android-фрагменты #android-recyclerview

Вопрос:

Еще раз здравствуйте, ребята, вы были полезны на прошлой неделе с моим путешествием по изучению kotlin и моим первым приложением kotlin. я создаю приложение для составления списка покупок, поэтому я использую RecycleView для представления списка покупок внутри каждого элемента списка покупок, у пользователя есть 2 кнопки (плюс и минус), которые позволяют ему выбирать, сколько из этого товара он хотел бы приобрести. на данный момент я настраиваю только кнопку «Плюс», но каждый раз, когда я обновляю свою базу данных на новое количество товара, она не использует мою функцию «обновить список», и я не могу найти способ вызвать эту функцию после завершения моей функции «добавления» К вашему сведению: весь shopping_list находится внутри фрагмента. это файл shopping_list.kt

 package com.example.pricetag.fragments

import android.app.AlertDialog
import android.content.Context
import android.content.DialogInterface
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageButton
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.pricetag.R
import com.example.pricetag.fragments.DTO.ItemList
import com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlinx.android.synthetic.main.fragment_shopping_list.*


lateinit var dbHandler: DBHandler

class shopping_list() : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        
    
        val view = inflater.inflate(R.layout.fragment_shopping_list, container, false)
        dbHandler = DBHandler(view.context)

        val addItem_button = view.findViewById<FloatingActionButton>(R.id.fab_shoppiglist)


        addItem_button.setOnClickListener {
            val dialog = AlertDialog.Builder(getContext())
            val tempView = layoutInflater.inflate(R.layout.dialog_shoppinglist,null)
            val text_result = tempView.findViewById<EditText>(R.id.et_Itemlist)
            dialog.setView(tempView)
            dialog.setPositiveButton("Add") { _: DialogInterface, _: Int ->
                if (text_result.text.isNotEmpty()) {
                    val itemList = ItemList()
                    itemList.name = text_result.text.toString()
                    dbHandler.addItem(itemList)
                    refreshList()
                }


            }
            dialog.setNeutralButton("DeleteList") { _: DialogInterface, _: Int ->
                    dbHandler.delete()
                    refreshList()
            }
            dialog.setNegativeButton("Cancel"){ _: DialogInterface, _: Int->

            }
            dialog.show()
        }

        return view
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        rv_shoppinglist.layoutManager = LinearLayoutManager(activity)
        val verticalDecoration = DividerItemDecoration(
            rv_shoppinglist.getContext(),
            DividerItemDecoration.VERTICAL
        )
        val verticalDivider =
            ContextCompat.getDrawable(activity!!, R.drawable.rv_divider)
        verticalDecoration.setDrawable(verticalDivider!!)
        rv_shoppinglist.addItemDecoration(verticalDecoration)

    }


    override fun onResume() {
        refreshList()
        super.onResume()
    }

    private fun refreshList(){
        rv_shoppinglist.adapter = ShoppinglistAdpter(this.requireContext(), dbHandler, dbHandler.getItem())
    }


    class ShoppinglistAdpter(val context: Context, dbHandler: DBHandler,  val list: MutableList<ItemList>): RecyclerView.Adapter<ShoppinglistAdpter.ViewHolder>(){

        override fun onCreateViewHolder(p0: ViewGroup, pl: Int): ViewHolder {
            return ViewHolder(LayoutInflater.from(context).inflate(R.layout.rv_child_shoppinglist,p0,false))
        }

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

        override fun onBindViewHolder(holder: ViewHolder, p1: Int) {
            holder.itemName.text = list[p1].name
            holder.itemAmount.text = list[p1].amount.toString()
            holder.addButton.setOnClickListener{
                dbHandler.changeAmount(list[p1].id.toInt())
            }

        }

        class ViewHolder(v : View) : RecyclerView.ViewHolder(v){
            val itemName : TextView = v.findViewById(R.id.tv_item_name)
            val itemAmount : TextView = v.findViewById(R.id.tv_item_amount)
            val addButton : ImageButton = v.findViewById(R.id.IB_add)

        }

    }

}



  

дайте мне знать, если вам понадобится еще один фрагмент кода, чтобы я добавил к этому сообщению, чтобы вы могли мне помочь

Ответ №1:

Я тоже новичок в Kotlin, но я предлагаю вам попробовать это:

1. Добавьте адаптер в качестве переменной lateinit

 lateinit var dbHandler: DBHandler
lateinit var adapter: ShoppinglistAdpter

class shopping_list() : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        
    
        val view = inflater.inflate(R.layout.fragment_shopping_list, container, false)
        dbHandler = DBHandler(view.context)
        adapter = ShoppinglistAdpter(this.requireContext(), dbHandler, dbHandler.getItem() as ArrayList<ItemList>)

        rv_shoppinglist.adapter = adapter

  

2. Добавьте список переменных в RecyclerView.Адаптер, как показано ниже.

 class ShoppinglistAdpter(val context: Context, dbHandler: DBHandler): RecyclerView.Adapter<ShoppinglistAdpter.ViewHolder>(){

    var list: ArrayList<ItemList> = ArrayList()
        set(value) {
            field = value
            Log.d("List changed and value size is ${value.size}")
            notifyDataSetChanged()
        }
    
    override fun onCreateViewHolder(p0: ViewGroup, pl: Int): ViewHolder {
        return ViewHolder(LayoutInflater.from(context).inflate(R.layout.rv_child_shoppinglist,p0,false))
    }

    override fun getItemCount(): Int = list.size

    override fun onBindViewHolder(holder: ViewHolder, p1: Int) {
        holder.itemName.text = list[p1].name
        holder.itemAmount.text = list[p1].amount.toString()
        holder.addButton.setOnClickListener{
            dbHandler.changeAmount(list[p1].id.toInt())
        }

    }
}
  

Тогда вместо регулярного переназначения адаптера вызовите это:

 private fun refreshList(){
    adapter.list = dbHandler.getItem() as ArrayList<ItemList>
// adapter.list will call notifyDataSetChanged - this, I think, was the problem you were facing
}
  

Комментарии:

1. попробовал и получил эту ошибку java.lang.RuntimeException: не удается запустить activity ComponentInfo{com.example.pricetag/com.example.pricetag. DashbordActivity}: java.lang. Исключение IllegalStateException: rv_shoppinglist не должно быть нулевым

2. Вы пробовали использовать привязку к просмотру в своем фрагменте? Возможно, это предотвратит вышеуказанную ошибку.

Ответ №2:

Хорошо, я нашел решение, я опубликую его, надеюсь, это поможет кому-то в этой функции, это было просто, поскольку я пробовал это раньше, но вместо использования «This» я использовал «shoppinglist ()», который, я полагаю, должен был стать новым объектом ShoppingList

итак, что я сделал, это добавил внутри списка аргументов ShoppinglistAdapter «val ShoppingList: shopping_list, а затем вызвал метод refreshlist, где мне это было нужно

 
    class ShoppinglistAdpter(val context: Context, val shoppingList: shopping_list, dbHandler: DBHandler, val list: MutableList<ItemList>): RecyclerView.Adapter<ShoppinglistAdpter.ViewHolder>(){

        override fun onCreateViewHolder(p0: ViewGroup, pl: Int): ViewHolder {
            return ViewHolder(LayoutInflater.from(shoppingList.context).inflate(R.layout.rv_child_shoppinglist,p0,false))
        }

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

        override fun onBindViewHolder(holder: ViewHolder, p1: Int) {
            holder.itemName.text = list[p1].name
            holder.itemAmount.text = list[p1].amount.toString()
            holder.addButton.setOnClickListener{
                dbHandler.changeAmount(list[p1].id.toInt())
                shoppingList.refreshList()
            }

        }

        class ViewHolder(v : View) : RecyclerView.ViewHolder(v){
            val itemName : TextView = v.findViewById(R.id.tv_item_name)
            val itemAmount : TextView = v.findViewById(R.id.tv_item_amount)
            val addButton : ImageButton = v.findViewById(R.id.IB_add)

        }

    }
  

Комментарии:

1. Я видел, что вы добавили функцию refreshList внутри вашего OnClickListener. Но для вашего следующего проекта попробуйте использовать библиотеку groupie. Это делает использование recyclerview намного проще и увлекательнее