'Android | Update RecyclerView Adapter on ViewHolder onClick
I expect my 'heart' icon to change when my ViewHolder item is clicked. Fortunately, it does this. However, an issue arises as multiple items seems to replicate the button click.
What I mean is: If I tap the heart on item number 1. Other items throughout the list replicate also change the heart. Why is this happening and what is a potential fix? I am confused why this issue is occuring as I am referencing the ViewHolder item. Thus, shouldn't it only affect the item I am clicking?
View Holder
fun bind(item: Location) {
heart.setOnClickListener {
item.fav = item.fav != true
heart.setImageDrawable(
when (item.fav) {
false -> (ContextCompat.getDrawable(itemView.context, R.drawable.ic_border_heart))
else -> (ContextCompat.getDrawable(itemView.context, R.drawable.ic_whole_heart))
})
}
}
Solution 1:[1]
You didn't check the view ID in the onClick method. You can set onClick directly on the views as below.
class LocationViewHolder(v: View): RecyclerView.ViewHolder(v), View.OnClickListener {
private val actLoc: TextView = v.findViewById(R.id.location_main)
private val genLoc: TextView = v.findViewById(R.id.location_subtitle)
private val heart: ImageView = v.findViewById(R.id.heart)
private lateinit var item: Location
fun bind(item: Location) {
this.item = item
actLoc.setText(item.actualLocation)
actLoc.setOnClickListener {
Toast.makeText(itemView.context, "${item.cords}", Toast.LENGTH_SHORT).show()
}
genLoc.setText(item.genLocation)
genLoc.setOnClickListener {
Toast.makeText(itemView.context, "${item.cords}", Toast.LENGTH_SHORT).show()
}
heart.setOnClickListener {
item.fav = item.fav != true
heart.setImageDrawable(
when (item.fav) {
false -> (ContextCompat.getDrawable(itemView.context, R.drawable.ic_border_heart))
else -> (ContextCompat.getDrawable(itemView.context, R.drawable.ic_whole_heart))
})
}
}
Solution 2:[2]
However, an issue arises as multiple items seems to replicate the button click.
it is because of the cell recycling mechanism
heart.setImageDrawable(
when (item.fav) {
false -> (ContextCompat.getDrawable(itemView.context, R.drawable.ic_border_heart))
else -> (ContextCompat.getDrawable(itemView.context, R.drawable.ic_whole_heart))
})
should be part of the bind function in the viewholder and not part of the onClick function. What I would expect is
- Click informs the viewmodel
- Viewmodel update the dataset
- Viewmodel informs the recyclerview
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jennifer Karling |
| Solution 2 | Blackbelt |
