How to implement the android ViewHolder Design Pattern
One of the most important features of a list in an app is how smoothly it scrolls. Many little details like this add up to either a great or frustrating experience for users. Now, we obviously want our app to be delightful, so we need to learn what we can do as developers.
To make our lists as smooth and efficient as possible. The main idea we are going to focus on is recycling views for items on the list. As one item scrolls off the screen, we can reuse its view components for the one that scrolls onto the screen.
Imagine we had 1,000 items to display with a list only showing a handful
at a time on the screen. We don't want to create 1,000 views and hold them
in memory. Especially if the user doesn't end up scrolling through
anything. Android takes a just-in-time approach and creates a display for
items in a list. Right when they are needed on the screen.
What is ViewHolder Pattern?
According to
Google Developer Blog,
Your code might callfindViewById()
frequently during the scrolling of ListView, which can slow down performance. Even when the Adapter returns an inflated view for recycling, you still need to look up the elements and update them. A way around repeated use offindViewById()
is to use the "view holder" design pattern.
In simple words, the ViewHolder
pattern skips the step of
calling findViewById()
every time when row loads in view.
It stores all views in an object when the first time to view loads and
then it allows the adapter to reuse views without calling
findViewById()
. That means your adapter will call
findViewById()
only when it will not find any data/object
for the views or you can say it will call findViewById()
when the object is null.
How ViewHolder design pattern works?
-
The first time it was loaded,
convertView
isnull
. We’ll have to inflate our list item layout and find the TextView viafindViewById()
. -
The second time it was loaded,
convertView
is notnull
, good! We don’t have to inflate it again. But we’ll usefindViewById()
again. -
The following times it was loaded,
convertView
is definitely not null. ButfindViewById()
is constantly called, it will work but, it slows down the performance especially if you have lots of items and Views in your RecyclerView.
Let's see how to implement a view holder pattern with an example.
We will use the below
ViewHolderItem
class as an example.
static class ViewHolderItem { TextView textViewItem; }
Now let's see how we can use it in
getView()
method.@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolderItem viewHolder; if(convertView==null){ // inflate the layout LayoutInflater inflater = ((Activity) mContext).getLayoutInflater(); convertView = inflater.inflate(layoutResourceId, parent, false); // well set up the ViewHolder viewHolder = new ViewHolderItem(); viewHolder.textViewItem = (TextView) convertView.findViewById(R.id.textViewItem); // store the holder with the view. convertView.setTag(viewHolder); }else{ // we've just avoided calling findViewById() on resource everytime // just use the viewHolder viewHolder = (ViewHolderItem) convertView.getTag(); } // object item based on the position ObjectItem objectItem = data[position]; // assign values if the object is not null if(objectItem != null) { // get the TextView from the ViewHolder and then set the text (item name) and tag (item ID) values viewHolder.textViewItem.setText(objectItem.itemName); viewHolder.textViewItem.setTag(objectItem.itemId); } return convertView; }
A
ViewHolder
object stores each of the component views inside
the tag field of the Layout, so you can immediately access them without
the need to look them up repeatedly.