You will have several ViewHolder objects.
A ListView by its nature, does not create new instances of View for each of its rows. This is so that if you have a ListView of a million things, you don’t need to store layout information for a million things. So what do you need to store? Just what is on the screen. Then you can reuse these views over and over again. Thus, your ListView of a million objects can have only 10 child views.
In your custom array adapter, you get a function called getView() that looks something like this:
public View getView(int position, View convertView, ViewGroup parent) {
It will work, but take a moment and see if you can find inefficiency here. Consider which of the above codes will be called redundant.
The problem is that we call row.findViewById again and again, even if we don’t change it after the first search. Although, if you only have a simple TextView in your list, it is probably not so bad if you have a complex layout or you have several views on which you want to set the data, you can lose a little time finding your look again and again.
So how do we fix this? Well, it would be wise to keep this TextView somewhere after we look at it. So, we introduce a class called a ViewHolder that “holds” views. Therefore, inside the adapter, enter the inner class as follows:
private static class ViewHolder { TextView textView; }
This class is private, because it is just a caching mechanism for the adapter, and it is static, so we don’t need a link to the adapter to use it.
This will keep our view, so we do not need to call row.findViewById several times. Where should we install it? When we first blow out the show. Where do we keep it? Views have their own tag field, which can be used to store meta-information about the view - exactly what we want! Then, if we have already seen this view, we just need to search for the tag instead of looking for each of the views within the string.
So, the if statement inside getView() becomes:
Now we just need to update the text value of holder.textView, since it already refers to the redesigned view! Therefore, our final adapter code will look like this:
public View getView(int position, View convertView, ViewGroup parent) {
And you're done!
Some things to think about:
- How will this change if you have several views in a row that you want to change? As a task, create a ListView where each row has two
TextView and ImageView objects - When debugging a ListView, check a few things so that you can really see what is happening:
- How many times the ViewHolder constructor is called.
holder.textView.getText() value before updating at the end of getView()