Search code examples
androidkotlinandroid-recyclerviewdata-binding

RecyclerView items changes randomly on clicking an item


I have a RecyclerView list, I want the color of the clicked item to be changed. But whenever I am clicking an item the RecyclerView items change randomly.

I have also taken a boolean in my data class to keep track of item selection.

data class

data class OrderAvailableDaysResponseItem(
val actual_date: String,
val day_name: String,
val date_name: String,
val day_num: Int,

// For item selection
var isDateSelected: Boolean)

Inside my fragment, checking if the clicked item matches the list item and updating the isDateSelected to true, then calling notifydatasetchanged.

private var availableDaysList: OrderAvailableDaysResponse = OrderAvailableDaysResponse()
orderAvailableDaysAdapter.setDateClickListener {
        for(resItem in availableDaysList){
            resItem.isDateSelected = resItem.date_name == it.date_name
        }
        orderAvailableDaysAdapter.notifyDataSetChanged()
    }

Adapter clicklistener

var onDateClickListener: ((OrderAvailableDaysResponseItem) -> Unit)? = null
fun setDateClickListener(listener: (OrderAvailableDaysResponseItem) -> Unit){
    onDateClickListener = listener
}

inner class AvailableDaysViewHolder(binding: ItemAvailableDaysBinding) : RecyclerView.ViewHolder(binding.root) {
    fun setBindings(itemRes: OrderAvailableDaysResponseItem){
        binding.resItem = itemRes
        binding.executePendingBindings()

        binding.clRoot.setOnClickListener {
            onDateClickListener?.let {
                it(itemRes)
            }
        }

    }
}

Please refer to the attachment for a better understanding of the situation

enter image description here

As you can see on clicking on an item the items are changing randomly. Please help me. Am I missing something?

Edit 1:

Complete adapter code

class OrderAvailableDaysAdapter(var orderAvailableDaysResponseList: OrderAvailableDaysResponse) : RecyclerView.Adapter<OrderAvailableDaysAdapter.AvailableDaysViewHolder>() {

private lateinit var binding: ItemAvailableDaysBinding

var onDateClickListener: ((OrderAvailableDaysResponseItem) -> Unit)? = null
fun setDateClickListener(listener: (OrderAvailableDaysResponseItem) -> Unit){
    onDateClickListener = listener
}

inner class AvailableDaysViewHolder(binding: ItemAvailableDaysBinding) : RecyclerView.ViewHolder(binding.root) {
    fun setBindings(itemRes: OrderAvailableDaysResponseItem){
        binding.resItem = itemRes
        binding.executePendingBindings()

        binding.clRoot.setOnClickListener {
            onDateClickListener?.let {
                it(itemRes)
            }
        }
    }
}

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

override fun onBindViewHolder(holder: AvailableDaysViewHolder, position: Int) {
    holder.setBindings(orderAvailableDaysResponseList[position])
}

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

Solution

  • remove private lateinit var binding: ItemAvailableDaysBinding from adapter, don' keep it "globally", initialisation is made only once, in onCreateViewHolder

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

    same naming of this "global" object and in AvailableDaysViewHolder inner class may confuse it and setBindings may be called on lastly initialised (global kept) object rather that this passed in constructor