VOOZH about

URL: https://www.javacodegeeks.com/2013/09/android-viewholder-pattern-example.html

⇱ Android ViewHolder Pattern Example


Now we are going to code the smooth scrolling of our Android ListView. In the previous post, we tried to understand how the ListView with adapter works. This time, it will be all about performance.

I did this a separate post because Android ListView is difficult to understand at times. What I have in mind is, “we have to do the basics first, and then apply the optimization.”

What’s with the ViewHolder pattern?

The ViewHolder design pattern enables you to access each list item view without the need for the look up, saving valuable processor cycles. Specifically, it avoids frequent call of findViewById() during ListView scrolling, and that will make it smooth.

Without the ViewHolder Design Pattern

Okay, let’s dig it out and see how it works without the ViewHolder pattern.

Let’s take a look at our previous getView() method in ArrayAdapterItem.java

  1. The first time it was loaded, convertView is null. We’ll have to inflate our list item layout and find the TextView via findViewById().
  2. The second time it was loaded, convertView is not null, good! We don’t have to inflate it again. But we’ll use findViewById() again.
  3. The following times it was loaded, convertView is definitely not null. But findViewById() is constantly called, it will work but, it slows down the performance especially if you have lots of items and Views in your ListView.

With the ViewHolder Design Pattern

Now let’s see how it works with the ViewHolder pattern.

  1. The first time it was loaded, convertView is null. We’ll have to inflate our list item layout, instantiate the ViewHolder, find the TextView via findViewById() and assign it to the ViewHolder, and set the ViewHolder as tag of convertView.
  2. The second time it was loaded, convertView is not null, good! We don’t have to inflate it again. And here’s the sweet thing, we won’t have to call findViewById() since we can now access the TextView via its ViewHolder.
  3. The following time it was loaded, convertView is definitely not null. The findViewById() is never called again, and that makes our smooth ListView scrolling.

Let’s Code!

So here it is, we’ll make use of the Android ViewHolder pattern in our ListView (in just 3 steps!).

Step 1: Add the following static class on our ArrayAdapterItem.java file

// our ViewHolder.
// caches our TextView
static class ViewHolderItem {
 TextView textViewItem;
}

Step 2: Our getView() will now look like this:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

 ViewHolderItem viewHolder;

 /*
 * The convertView argument is essentially a "ScrapView" as described is Lucas post 
 * http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
 * It will have a non-null value when ListView is asking you recycle the row layout. 
 * So, when convertView is not null, you should simply update its contents instead of inflating a new row layout.
 */
 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;

}
Want to create a kick-ass Android App ?
Subscribe to our newsletter and download the Android UI Design mini-book right now!
With this book, you will delve into the fundamentals of Android UI design. You will understand user input, views and layouts, as well as adapters and fragments. Furthermore, you will learn how to add multimedia to an app and also leverage themes and styles!

Thank you!

We will contact you soon.


Step 3: For the sake of testing, we’re going to put thousands of items in our ListView. On our MainActivity.java, our showPopUp() will now look like this:
public void showPopUp(){

 // we'll specify the number of items we want our ListView to have.
 int numberOfItems = 1000;

 // add your items, this can be done programatically
 // your items can be from a database
 ObjectItem[] ObjectItemData = new ObjectItem[numberOfItems];

 // we'll use a for loop 
 // created objects = number of items specified above
 for(int x=0; x<numberOfItems; x++){

 int sampleId = 90 + x;
 ObjectItemData[x] = new ObjectItem(sampleId, "Store # " + (x+1));

 }

 // our adapter instance
 ArrayAdapterItem adapter = new ArrayAdapterItem(this, R.layout.list_view_row_item, ObjectItemData);

 // create a new ListView, set the adapter and item click listener
 ListView listViewItems = new ListView(this);
 listViewItems.setAdapter(adapter);
 listViewItems.setOnItemClickListener(new OnItemClickListenerListViewItem());

 // put the ListView in the pop up
 alertDialogStores = new AlertDialog.Builder(MainActivity.this)
 .setView(listViewItems)
 .setTitle("Stores")
 .show();

}

I tested this code with as much as 2,000 items, and the performance is still smooth and great.

What’s Next?

If you have other ideas regarding this topic, please drop it in the comment section below. I’m more than willing to update this post and improve the life of mankind.

In the next post, we’ll try to use the AsyncTask to load image into the ListView. Something like how the Google Play Store app does it.
 

Reference: Android ViewHolder Pattern Example from our JCG partner Mike Dalisay at the The Code of a Ninja blog.
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Thank you!

We will contact you soon.

👁 Photo of Mike Dalisay
Mike Dalisay
September 20th, 2013Last Updated: December 5th, 2023
17 3,175 3 minutes read
Subscribe

This site uses Akismet to reduce spam. Learn how your comment data is processed.

17 Comments
Oldest
Newest Most Voted
Bill Mote
12 years ago

Interested in why you named your class ViewHolderItem? Every implementation I’ve ever seen (and that’s a lot) uses ViewHolder. Why deviate from the norm in this case?

0
Reply
J & J
12 years ago

What will be a solution when row views are no equal? Where they can be cached instead of inflating each time?

0
Reply
Olivier Mwamimwiza
6 years ago
Reply to  J & J

I think in that case you should use Layout Manager from the RecycleView tricks.

0
Reply
rahul bawa
12 years ago

import java.util.ArrayList; import android.content.Context; import android.content.res.Resources; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; public class TypeOfConcurAdapter extends BaseAdapter { private Context context; private ArrayList typeOfConcur; private int size; private LayoutInflater inflater = null; private Holder holder; private ConcurType concurType; public TypeOfConcurAdapter(Context context, ArrayList typeOfConcur) { // TODO Auto-generated constructor stub this.context = context; this.typeOfConcur = typeOfConcur; this.size = this.typeOfConcur.size(); this.inflater = (LayoutInflater) this.context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getCount() { // TODO Auto-generated method stub return this.size; } @Override public Object getItem(int pos) { // TODO Auto-generated method stub return this.typeOfConcur.get(pos);… Read more »

0
Reply
Abdul
12 years ago

hi ur tutorial is superb . I got more idea on this. but i have doubt how can you add image with like buttons inside listview i am working on this not able to get resolution on that.

0
Reply
Muhammad Ali Rafique
11 years ago
Reply to  Abdul

viewHolder.ImageViewImagepath = (ImageView) view.findViewById(R.id.imageView1);
viewHolder.ImageViewImagepath.setImageBitmap(myBitmap);

0
Reply
rahul
12 years ago

The problem with image buttons or normal buttons is that they consume the click instead of throwing click down to list item.So to avoid it use image view instead or aetfocussable on your image button to false.

0
Reply
11 years ago

Why are you using

ObjectItem objectItem = data[position];

and not the supplied getItem method ie.

ObjectItem objectItem = getItem(position);

??

0
Reply
Muhammad Ali Rafique
11 years ago

Its just for getting data to populate Text View its not related to View holder

0
Reply
anish yesudasan
10 years ago

Hi used CustomListAdapter class which extends baseadapter. In that i have a button on each view of the list view ..when i lick on the button it should print a text. everything is working fine except that the text is printed in someother view too. i am using view holder and also checked the position and the positions of view in listview is repeating. @Override public View getView( int position, final View convertView, ViewGroup parent) { // view = null; view = convertView; final ViewHolder viewHolder; // pos = getItemViewType(position); // long posn = getItemId(position); // final int paps= (int)posn… Read more »

0
Reply
Anmol Gandhi
9 years ago

If you got your answer from somewhere then please share it with me also please, coz i am also held in the same situation from few weeks and not getting a proper solution.

0
Reply
Valentin
9 years ago

Hi. Please somebody tell me why the ViewHolder class must be static? Thank you very much in advance.

0
Reply
Hitesh Bhutani
9 years ago
Reply to  Valentin

It has to be static because it has to hold the references of different widgets within it. If you won’t make it static then in that case, you have to create a new object of this class which will be destroyed when one view is created and thus the problem wil still be there.

0
Reply
Justin Kalis
9 years ago

Can you give an example of leveraging the power of viewfinder patterns for button views in a linearlayout? I have a layout which has 90 buttons and it inflates into a viewpager which is baggy due to high number of buttons in layout along with possible penalty for nested weights which are known to be bad for performance plus lint complains of these as well. Also is it better to use relative layout for performance to avoid nesting and will this have any impact on using viewholder patterns, I want no lag and once I get this figured out for… Read more »

0
Reply
Mohamma Amin
7 years ago

Thanks, it’s very brief and useful.

0
Reply
Olivier Mwamimwiza
6 years ago

Thank you for your tutorial, it was helpful for me, have been using it but couldn’t really get it right

1
Reply
Ivan Pursheha
6 years ago

yeah, I just had understood this too (:

0
Reply
Back to top button
Close
wpDiscuz