androidkotlinandroid-recyclerviewlistadapterandroid-diffutils

List Adapter Diff Util not updating the List Item in Recyclerview


List Adapter diffutil not updating the list item in recyclerview.

It works when I add or remove a item from the list. But not updating the any particular value like isSelected : Boolean = false in object class

How to update the recyclerview view when one of the object class in list is changed like value Boolean changes in one object class

Thankyou

Adapter Class Below

class CategoryMainAdapter(
    var itemClick : CategoryItemClick,
    var screenWidth : Int = 0
) : ListAdapter<CategoryModel, CategoryMainAdapter.CategoryMainViewHolder>(CategoryMainDiffUtils()) {

    inner class CategoryMainViewHolder(val binding : CategorySingleListLayoutBinding) : RecyclerView.ViewHolder(binding.root)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryMainViewHolder {
        val binding = CategorySingleListLayoutBinding.inflate(LayoutInflater.from
            (parent.context),
            parent,
            false
        )
        return CategoryMainViewHolder(binding)
    }

    override fun onBindViewHolder(holder: CategoryMainViewHolder, position: Int) {
        val model = getItem(position)
        holder.apply {
            binding.apply {
                mainLinearLayout.layoutParams.apply {
                    width = ((screenWidth*22.5).toInt())/100
                    height = (((screenWidth*22.5)/100)*1.2).toInt()
                }
                categoryName.text = model.name
                backgroundColor.setBackgroundColor(model.colorCode)
                categoryImage.load(getImageCorrectImage(model.image, model.secondaryImage)) {
                    error(R.drawable.ic_food_place_holder)
                }

                if (model.isSelected) {
                    categoryName.setTextColor(ContextCompat.getColor(categoryName.context, R.color.main_blue))
                    selectedView.setBackgroundResource(R.drawable.main_blue_curved_bg)
                    categoryImage.apply {
                        animation = AnimationUtils.loadAnimation(context, R.anim.category_zoom_in_anim)
                        setPadding(0, 0, 0, 0)
                    }
                } else {
                    categoryName.setTextColor(setColorByAttrProgrammatically(categoryName.context, R.attr.colorOnSecondary))
                    selectedView.setBackgroundResource(android.R.color.transparent)
                    categoryImage.apply {
                        animation = AnimationUtils.loadAnimation(context, R.anim.category_zoom_out_anim)
                        setPadding(1, 1, 1, 1)
                    }
                }
            }
            itemView.apply {
                setOnClickListener {
                    itemClick.onCategoryClick(model)
                }
            }
        }
    }


    class CategoryMainDiffUtils : DiffUtil.ItemCallback<CategoryModel>() {
        override fun areItemsTheSame(oldItem: CategoryModel, newItem: CategoryModel): Boolean {
            return oldItem.isSelected == newItem.isSelected
        }

        override fun areContentsTheSame(oldItem: CategoryModel, newItem: CategoryModel): Boolean {
            return oldItem == newItem
        }

    }

    override fun submitList(list: MutableList<CategoryModel>?) {
        super.submitList(list?.let { ArrayList(it) })
    }
}


Solution

  • First of, the implementation of areContentsTheSame and areItemsTheSame probably needs to be switched. areContentsTheSame is the one that checks if things in your items are different. areItemsTheSame is about whether it is the same item. If the items have an id you might want to compare them instead of the item themselves. But that alone probably won't fix your issue.

    The thing is, ListAdapter works best if the list has items that are immutable. Ideally you want to submit a new list every time you call submitList. Because if you change a property like isSelected in the existing lisk and simply call submitList with that same list nothing will happen.

    So what you want to do is instead of changing the isSelected property you need to create a copy of the list and in that copy alone you change the isSelected and pass the copy to submitList.

    This can be tedious to make. An alternative ugly workaround that might work is to add a second property maybe called oldIsSelected and only change that one in the DiffUtil itself, like this

        override fun areContentsTheSame(oldItem: CategoryModel, newItem: CategoryModel): Boolean {
            val result = oldItem.oldIsSelected == newItem.isSelected
            newItem.oldIsSelected = newItem.isSelected
            return result
        }