About this post
The View Holder design pattern is one of the most important ways to increase the performance of an Android application with a
ListView. However, most of the Android projects I review at Udacity entirely omit this pattern. Personally, I think that Android itself is to be blamed here. View Holder is not a complicated pattern, but it takes a bit of getting used to, and the benefits may not be that visible, so students may prefer to build their applications in the simplest way and move onto the next project.
But, once you learn how a View Holder works and how to implement one you will never go back. And it will be a lot easier for you to move onto a
RecyclerView, which is a lot more powerful and flexible view comparing to a
ListView. I’m planning to cover a
RecyclerView in one of the upcoming posts.
About a List View
ListView is designed to tackle the problem of displaying a long or even huge list of items. Some examples may include a list of contacts, songs, your favorite coffee shops, latest transactions of your bank account or many others. The challenge here is that users can only see a small portion of these items. A user will never be able to see all of their 4579 songs at the same time, but rather a small portion of them.
It does not make sense to try to render the whole list at once. It would take a significant amount of time, device memory and may be unnecessary as users may be interested in the third item of the list and never scroll to the bottom.
To increase the performance of scrolling, a
ListView would “recycle” its views, by taking a view which is no longer visible to the users and appending it at the bottom of the list, as shown below.
This is already a very efficient process, the only problem here is the
findViewById() method, which is pretty slow and depending on the complexity of a list item it may be called multiple times per item, here is a simple example.
As you can see in the code above, the
findViewById method is called three times and this is done every single time we display a new item on the screen. However, once we implement the
ViewHolder design pattern this will no longer be required.
You can open the project with Android Studio, compile and run it. It is a very simple application which is designed to mock a contacts list.
You can refer to the Contact.java and MockDataGenerator.java classes if you are interested in looking under the hood of the application. The first one is a Model class, which contains the first and the last name of a person as well as their contact numbers. And
MockDataGenerator is used to generate a
List of random contacts.
Most important, however, is the
ListViewActivity.java file, so let’s have a closer look at it.
There are two classes in this file. Keeping different classes in the same file is not always the best practice, but I did this to make the tutorial simpler so that we don’t have to navigate between multiple different files. First class is called
ListViewActivity and it extends
AppCompatActivity, this is very standard. And the class implements a single method only.
In this method we attach the activity_list_view layout file as the main view, then we find the
ListView inside of that layout and assign a new instance of the
ContactsAdapater to it.
ContactsAdapter has three methods. First, we have a constructor. It accepts an instance of
Context and passes it to the
super class. And then it instantiates the local variable called
contacts with a list of 1000 random contacts.
Then we have a method called
getCount() which returns the size of the local variable called
And lastly we have our
getView() method which is responsible for inflating and recycling the views. The method is checking if the
convertView parameter is
null and inflates a new instance of the contact_item view if it is.
In either case, we take this view, locate the three text views inside of it and fill them up with a relevant instance of the
Adding a ViewHolder
The purpose of a view holder is to hold ._. references to the views. So, rather than trying to find a view by its identifier each time it is about to appear on the screen, we only need to do this once and then use the reference to modify the content.
We’ll start by creating a new
class. This class can be located inside of the
ContactsAdapter class for now. There are three text views inside of the list item, so our view holder needs to have three references. Here it is:
Now let’s add a constructor. The constructor needs to accept a reference to a
View and instantiate all of the references to the
private variables. This code will probably feel familiar.
And this is all we need to do to implement the class itself! Now we just need to make sure to use it inside of our adapter. The only place we need to change is our
We need to create a new instance of a
ViewHolder every time we inflate a list item. And then we store this reference. This is where
setTag() method becomes very useful. We can assign any object to a view which we can retrieve later. Here is the modified code.
We also need to add an
else statement for those situations when the
convertView is already inflated. Here we just need to read the tag and cast it to the class.
The last part is to start using the
viewHolder to reference the views instead of our old code.