ListView/ExpandableListView randomly changes background colour on scroll/click/expand/collapse

Working on the same android app which I posted about a couple of times earlier, I had this one feature I wanted to implement where I show a list of persons and highlight those from that list who have a birthday today. I tried a couple of different approaches to to the "highlight" the list items which had a birthday today for e.g: setting the background colour for those items, setting up a background icon for those, changing the text colour of the list item, and with all of these I faced 1 common problem: if I had to scroll the list or expand/collapse one item group (in case of ExpandableListView), then it would end up highlighting some random items from the list, and if I continued that excercise, finally almost all items would get highlighted.

Since I had used an ExpandableListView, my getGroupView method looked somewhat like this:

@Override 
public View getGroupView(int groupPosition, ..., ViewGroup parent) {
  Person person = (Person) getGroup(groupPosition);
  
  if(convertView == null) { ... }
  
  if(person.hasBirthdayToday()) {
    ImageView birthdayIcon = (ImageView)convertView.findViewById(R.id.birthdayIcon);
    birthdayIcon.setImageResource(R.drawable.gift);
  } 

  ... 

  return convertView;
}

and this resulted in the view getting rendered this way:
I was quite happy with the result, until I started scrolling down in that list and then scrolling back up, which resulted in this:

to add to that, if I had to open an item in the expandable list view, and collapse it back, this is what would happen:
and as if that was not enough, if I continued scrolling up and down that list, this is what it resulted in:
Now, this was really frustrating, because I had no clue as to why that would be happening or how do I even start to solve this issue.

However that was not entirely true - I did have a feeling it might have something to do with the way the list items were being rendered/repainted. After spending almost two days searching for solutions on stackoverflow and other people who might've blogged about this issue, I came across Lucas Rocha's post:
Performance Tips for Android’s ListView.

What really helped me from that page was that small illustration that he has of what happens when you scroll down/up in a ListView/ExpandableListView.

The issue was that whenever my list item would go out of the viewport, there was no guarantee that it will show up the same way when it comes back into the viewport, because when a list item is to go on-screen, an existing ScrapView is picked up from the pool of ScrapViews. Now it is very much possible that the very ScrapView that is going on-screen was used for some other list item that just went off-screen. That would mean, my list items would show up properly as long as I reset everything that might've been set in the ScrapView when it was on-screen the last time.

More specifically, I was setting the gift icon in the list item if person.hasBirthdayToday() but I was never really resetting it if the condition evaluated to false. So, that would mean, if a ScrapView was used to show a list item with the gift icon, all subsequent list items that use the same ScrapView, would end up showing the same gift icon, and that was the reason why after scrolling up and down for a couple of times, I'd end up with almost all items having the gift icon with it.

Hence, my solution was to put an else block for resetting the birthdayIcon image, and here's how I did it:

@Override 
public View getGroupView(int groupPosition, ..., ViewGroup parent) {
  Person person = (Person) getGroup(groupPosition);
  
  if(convertView == null) { ... }
  
  ImageView birthdayIcon = (ImageView)convertView.findViewById(R.id.birthdayIcon);
  if(person.hasBirthdayToday()) {
    birthdayIcon.setImageResource(R.drawable.gift);
  } else {
    birthdayIcon.setImageResource(android.R.color.transparent);
  }

  ...

  return convertView;
}


With that else block in place, I was able to get exactly what I wanted - each list item to "remember" whether they should have a gift icon or not.



Comments

Popular posts from this blog

Errors while trying to monitor Asterisk through Nagios

Configuring remote access for couchdb

Proxy Error 502 “Reason: Error reading from remote server” with Apache 2.2.3