Tags
android, custom-ui, list-view, mozilla, optimization, view-holder
Android suggests using a ViewHolder pattern to optimize ListViews. There are many blogs about how to use it. Let’s take a simple example.
// Named as row.xml. This is just a skeleton. <RelativeLayout> <ImageView android:id="@+id/icon"/> <TextView android:id="@+id/title" android:layout_toLeftOf="@id/icon"/> <TextView android:id="@+id/subtitle" android:layout_toLeftOf="@id/icon" android:layout_below="@id/title"/> </RelativeLayout>
And the code with ViewHolder
and getView()
will look like this.
class ViewHolder { ImageView icon; TextView title; TextView subtitle; } // Inside the adapter public void getView(int position, View convertView, ViewGroup parent) { // if convertView is null, the view is newly inflated. // else, re-assign new values. ViewHolder holder; if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.row, null); // Set up the ViewHolder. holder = new ViewHolder(); holder.icon = (ImageView) findViewById(R.id.icon); holder.title = (TextView) findViewById(R.id.title); holder.subtitle = (TextView) findViewById(R.id.subtitle); // Store the holder with the view. convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } // Assign values holder.icon.setImageDrawable(some_image); holder.title.setText(some_text); holder.subtitle.setText(some_text); }
The reason for ViewHolder pattern is:
- The ListViews are optimized (as mentioned here).
- The number of calls to
findViewById()
reduces.
But wait! Did we just add code that resembles a veryLongStatementThatIsHardToInterpret? Also, isn’t ViewHolder a class? Then why can’t we make the complex row a CustomView?
// Custom class for ListRow public class ListRow extends RelativeLayout { private ImageView mIcon; private TextView mTitle; private TextView mSubtitle; public ListRow(Context context, AttributeSet attrs) { // RelativeLayout intializations happen here. LayoutInflater.from(context).inflate(R.layout.row, this); // Store the views. mIcon = (ImageView) findViewById(R.id.icon); mTitle = (TextView) findViewById(R.id.title); mSubtitle = (TextView) findViewById(R.id.subtitle); } public void setIcon(Drawable drawable) { mIcon.setImageDrawable(drawable); } public void setTitle(String text) { mTitle.setText(text); } public void setSubtitle(String subtitle) { mSubtitle.setText(text); } } // Inside the adapter public void getView(int position, View convertView, ViewGroup parent) { // if convertView is null, the view is newly inflated. // else, re-assign new values. ListRow row; if (convertView == null) { // Inflation happens automagically. row = new ListRow(context, null); convertView = row; } else { row = (ListRow) convertView; } // Assign values row.setIcon(some_image); row.setTitle(some_text); row.setSubtitle(some_text); }
Isn’t the so clear? And the code for the row is abstracted. So, the title can be wrapped inside a LinearLayout. The ImageView can be made to a CustomImageView with borders. But the adapter code remains simple with calls like
setIcon()
and setTitle()
.
Note: The XML file’s parent will now be <merge>
.
Pingback: Custom RelativeLayout class in ListView video
Pingback: Custom RelativeLayout class in ListView : Android Community - For Application Development
Pingback: Adding multiple clicking regions to an Android TextView | Professor Neurus
I think your suggestion makes a small improvement to the Adapter code, on the expense of over-complexifying the view. Think about it: the view and the adapter are bound by nature. Abstracting the view gives very litter improvement, but requires a hole new family of classes to follow (the View family). The viewholder pattern is a pojo, and thus does not require the developer to know anything except plain java syntax to understand. It shouldn’t take more than a few minutes to understand.
Ok, I’d like to use a custom viewholder pattern only not with ListViews. My question is can this method of caching viewpager pages be used with anything and not just ListViews? All of the examples I’ve found on the internet only give examples based on ListView code samples.
Specifically I’d like to be able to take a page with XML buttons managed by LinearLayout ViewGroups wrapped in TableLayout to improve the performance of the views during super fast swipes. Now the application does not call for super fast swipes but that won’t prevent the user from doing it and when they do it will be lagville.
Lagville for my app is cause by the garbage collection which creates enough of a pause to kills the 60 frames a second swipe/scroll rate. So the idea is to cache these pages using the custom view holder pattern techniques and accomplish smoother operation and no GC processes. I understand what I’m after can be achieved by eliminating the findViewbyid calls since once all of my views are in a view holder pattern the bound views can be references as a group with just one findViewbyid call. Is this correct.?
Really need help on this before I go offer and spend two months figuring this out for my app. I don’t want to waste time on this if this technique can only be used for ListViews and I’m a rookie developer at that.
Thanks for any help you peeps can offer me.