Don’t forget to check out my online course “Your First Android App with Java”
Tutorial Requirements
You must have a Developer IDE (I recommend Eclipse) and the Android SDK installed. Having an intermediate to advanced knowledge of Android and Java is also recommended. Since this tutorial is about the ListView
, it can be more applicable to those with a ListView
wired to a custom adapter.
The Problem
So you have an application with a ListView
and each row has a follows a hierarchy inflated from perhaps an XML layout file. For example, Pocket has a ListView
and each row contains an image thumbnail, a title, and a subtitle. Obviously there’s nothing in the Android default row layout that is akin to this. Let’s suppose our ListView
has one thousand entries. When your application has a ListView
, you must account for at least a thousand items being in that ListView
and the user scrolling through them. You will not have the same results if you are testing your application and it has ten entries versus a thousand entries. Scrolling through those one thousand entries is not going to be all that fluid. You may notice some skipped frames or maybe the images are taking time to load. This is due to the fact that for every entry a new View
is created. So if you have one thousand items, then one thousand new views are being created. This method is incredibly expensive in terms of memory.
The Solution
Let’s say you can fit 12 items on your phone’s screen. When you scroll downwards by one, Item 1 is no longer on screen. Item 1 gets tossed into the Recycler
that is managed in the internals of ListView
. Our objective is to take Item 1, change the text or image, and put it back in the ListView
as Item 13. A new View
was not created, it was simply recycled. All of this work is done in the adapter.
Implement the Solution
Implementing it is actually fairly straightforward. It will make scrolling through a list of one thousand View
s analogous to scrolling through 10 View
s. First, you need to identify what the hierarchy of your row items are. For this tutorial, let’s presume we have a title, subtitle, and image. Our ViewHolder
class would look like this:
static class ViewHolder {
TextView title;
TextView subtitle;
ImageView icon;
}
A variable for each user interface widget must be created. Then we input the following code in the getView
method of our adapter:
public View getView(int position, View convertView, ViewGroup parent) {
// Avoid unneccessary calls to findViewById() on each row, which is expensive!
ViewHolder holder;
/*
* If convertView is not null, we can reuse it directly, no inflation required!
* We only inflate a new View when the convertView is null.
*/
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item_pocket, null);
// Create a ViewHolder and store references to the two children views
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.title);
holder.subtitle = (TextView) convertView.findViewById(R.id.subtitle);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
// The tag can be any Object, this just happens to be the ViewHolder
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
// Bind that data efficiently!
holder.title.setText(someTitle[position]);
holder.subtitle.setText(someSubtitle[position]);
holder.icon.setImageBitmap((position % 2) == 0 ? bitmap1 : bitmap2);
return convertView;
}
With this new getView
method, you can efficiently populate and scroll through a list view. At first glance, it might not seem as much of a difference, but when comparing the “new view every time” method to the “view holder” method on multiple devices, performance can be increased by two or three times.
This a pattern that you should be using whenever creating a custom adapter.
If you like this tutorial, don’t forget to check out my online course “Your First Android App with Java”
Author: Mohit Deshpande