I have a list view populated by an array adapter following the ViewHolder pattern. Each row is fairly complex when someone clicks a button I want to increment a count displayed in that row as well as update a string of text in that row.
So far I have everything being populated correctly but when i click a button on one cell it changes the values on the next row as well if it has been created.
I’ve tried notifyDataSetChanged() but this repopulates the whole list, which is not ideal for my case.
since I’m defining my onClick() methods within the array adapter I have a RowHolder class that holds the row v as well as the item populating that row MainListItemof the list item.
class RowHolder{
View v;
MainListItem i;
RowHolder(View v, MainListItem i){
this.v = v;
this.i=i;
}
}
Here is a snippet from the onClick() of the button where h is the holder
h.loveButton.setBackgroundColor(Color.parseColor(rowHolder.i.brandLoveColor));
h.loveButton.setImageResource(R.drawable.lovewhite);
((ImageView)rowHolder.v.findViewById(R.id.lovebutton)).setImageResource(R.drawable.lovewhite);
rowHolder.v.findViewById(R.id.lovebutton).setBackgroundColor(Color.parseColor(rowHolder.i.brandLoveColor));
String newLovers = getLoverString(rowHolder.i,rowHolder);
h.lovers.setText(newLovers);
((TextView)rowHolder.v.findViewById(R.id.lovers)).setText(newLovers);
rowHolder.i.loverString = newLovers;
rowHolder.i.loved = true;
int tmp = rowHolder.i.loves
tmp = tmp + 1;
((TextView)rowHolder.v.findViewById(R.id.lovecount)).setText(String.valueOf(tmp));
h.lovecount.setText(String.valueOf(tmp));
rowHolder.i.loves = tmp;
When the button is clicked I change the value In the data supplying the listview as well as the data in the holder holding the view as well as the data displayed in the actual view.
This implementation works fairly well except for the fact that when I change the value in the actual view it ends up changing it for all visible rows.
If someone could help me figure out a better way to accomplish this it would be great.
This is one problem you need to solve. The views simply show the data. It is up to you to implement an adapter that is fast at refreshing the data. For example if you load bitmaps, then then cache them for later. Sure the first load may take time, but the second time can be instant.
Tying the item and the row together like this is not ideal. Android recycles the views which makes this difficult to keep straight. As you have found. I have found that the settag method for a view is very handy to deal with problems like this. If a view needs to know what item in the adapter it is associated with use setTag to track that. The adapter’s getView method is a perfect place to set this. I would remove the holder altogether from the design. Try to have very few places where the data is tied to the views.
Once you have separated the data from the view and made the adapter refresh fast. You only need to update the data and the everything else just works.
For more info read up on the Model-View-Controller Design pattern.