How to notify and update list when item has been deleted using Groupie RecyclerView library and Kotlin

Viewed 1881

I have a RecyclerView implemented with the Groupie library and I can delete an item from the list fine, however need to update the view to see the change. I'd like to have something like notifyDataSetChanged() instead, so the list updates immediately. I'm a bit confused at this stage though, tried a few different ways to get an interface from the class that hosts my view holder to be triggered from the fragment that holds the adapter but I think I'm stuck now if I could get some help please.

class RecyclerProductItem(
private val activity: MainActivity,
private val product: Product, private val adapterListener: AdapterListener
) : Item<GroupieViewHolder>() {

companion object {
    var clickListener: AdapterListener? = null
}

override fun bind(viewHolder: GroupieViewHolder, position: Int) {

    viewHolder.apply {

        with(viewHolder.itemView) {

            clickListener = adapterListener

            ivTrash.setOnClickListener(object : View.OnClickListener {
                override fun onClick(v: View?) {
                    if (clickListener != null) {
                        Toast.makeText(context, "delete method to be added here", Toast.LENGTH_SHORT).show()
                        clickListener?.onClickItem(position)
                    } 
                }
            })

        }

    }
}

override fun getLayout() = R.layout.recyclerview_item_row

interface AdapterListener {
    fun onClickItem(position: Int)
}

}

Here it's my fragment. I tried to add a section to the adapter to see if it would allow me to retrieve a listener for it, but as my listener should be triggered under a specific item within the layout, this may not be the best solution, although couldn't make this work either.

class ProductsListFragment : Fragment(), RecyclerProductItem.AdapterListener {

private lateinit var adapter: GroupAdapter<GroupieViewHolder>
private val section = Section()

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    return inflater.inflate(R.layout.fragment_products_list, container, false)
}

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

    val linearLayoutManager = LinearLayoutManager(activity)
    recyclerView.layoutManager = linearLayoutManager

    adapter = GroupAdapter()

    adapter.add(section)


    recyclerView.adapter = adapter

    loadProducts()

}


private fun loadProducts() {

    GetProductsAPI.postData(object : GetProductsAPI.ThisCallback {

        override fun onSuccess(productList: List<JsonObject>) {

            for (jo in productList) {

                val gson = GsonBuilder().setPrettyPrinting().create()
                val product: Product =
                    gson.fromJson(jo, Product::class.java)

                adapter.add(
                    RecyclerProductItem(
                        activity as MainActivity,
                        Product(
                            product.id,
                            product.title,
                            product.description,
                            product.price
                        ),adapterListenerToBePassedHere 
                    )
                ) // This part is where I should be giving the listener, but get a red line since not sure how to get it to include it here.

            }

        }

    })

}


companion object {
    fun newInstance(): ProductsListFragment {
        return ProductsListFragment()
    }
}


override fun onClickItem(position: Int) {
    
    adapter.notifyItemRemoved(position)
}

}

Many thanks.

2 Answers

I think you are missing this concept from the groupie Readme:

Modifying the contents of the GroupAdapter in any way automatically sends change notifications. Adding an item calls notifyItemAdded(); adding a group calls notifyItemRangeAdded(), etc.

So to remove an item, call section.remove(item). However, in your onClickItem function you currently only pass the position. Pass the item like clickListener?.onClickItem(this@RecyclerProductItem) instead. Even more ideally and safely you should remove by product.id, e.g. clickListener?.onClickItem(this@RecyclerProductItem.product.id) then in onClickItem() you just search for the item with that product id and remove it. Let me know if I'm not clear.

Based on @carson's reply, this is what worked for me. Had to add the items to the section, the section to the adapter and then remove the item from the section based on the adapter position once that listener is clicked, passing the method that implements the listener as one of the arguments to complete the GroupAdapter.

class RecyclerProductItem(
private val activity: MainActivity,
private val product: Product, private val adapterListener: AdapterListener
) : Item<GroupieViewHolder>() {

companion object {
    var clickListener: AdapterListener? = null
}

override fun bind(viewHolder: GroupieViewHolder, position: Int) {

    viewHolder.apply {

        with(viewHolder.itemView) {

            tvTitle.text = product.title

            clickListener = adapterListener

            ivTrash.setOnClickListener(object : View.OnClickListener {
                override fun onClick(v: View?) {
                    if (clickListener != null) {
                        Toast.makeText(context, "delete method to be added here", Toast.LENGTH_SHORT).show()
                        clickListener?.onClickItem(this@RecyclerProductItem.product.id, adapterPosition)
                    }
                }
            })

        }

    }
}

override fun getLayout() = R.layout.recyclerview_item_row

interface AdapterListener {
    fun onClickItem(id: Int, position: Int)
}

}

And

private fun loadProducts() {

    GetProductsAPI.postData(object : GetProductsAPI.ThisCallback,
        RecyclerProductItem.AdapterListener {

        override fun onSuccess(productList: List<JsonObject>) {

            Log.i(LOG_TAG, "onSuccess $LOG_TAG")

            for (jo in productList) {

                val gson = GsonBuilder().setPrettyPrinting().create()
                val product: Product =
                    gson.fromJson(jo, Product::class.java)

                val linearLayoutManager = LinearLayoutManager(activity)
                recyclerView.layoutManager = linearLayoutManager

                adapter = GroupAdapter()
                section.add(
                    RecyclerProductItem(
                        activity as MainActivity,
                        Product(
                            product.id,
                            product.title,
                            product.description,
                            product.price
                        ), this
                    )
                ) 

                adapter.add(section)
                recyclerView.adapter = adapter
            }

        }

        override fun onFailure() {
            Log.e(LOG_TAG, "onFailure $LOG_TAG")
        }

        override fun onError() {
            Log.e(LOG_TAG, "onError $LOG_TAG")
        }

        override fun onClickItem(id: Int, position: Int) {
            section.remove(adapter.getItem(position))
        }

    })

}
Related