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.