Programming and Personal Development

Android ListView Part 2

In part1 of this series, you learned what an adapter is and how it can be used to feed a simple ListView element.  Continuing from there, lets learn how to make some useful customizations to the ListView and a trick that android uses to optimize the usage of ListView elements for better performance.

Android ListView with multiple choice demo

ListView with multiple selections

MultiChoiceMode

Lets start with a simple customization. Lets reuse the example that we saw in part 1 and enable multi-selection on the drop down list.  To do this you need to make two simple changes,
  • Specify the “android:choiceMode” attribute in the XML layout as “multipleChoice”
  • Use the android.R.layout.simple_list_item_multiple_choice instead of android.R.layout.simple_list_item_1 as the TextView layout in the ArrayAdapter constructor.

Custom Layout for the ListView


Next, lets use a custom layout instead of the predefined layouts that we have been feeding into the constructor of the ArrayAdapter.  Lets customize by add a image before each string in the ListView. To keep it simple, we’ll be adding the default launcher image that comes with Android and resort to using a smaller font size. The resulting output is a ListView that looks as shown below.
  • Create a new xml layout with a ImageView and a TextView element. Specify the source attribute in the ImageView element to point to the launcher image in the res/drawable-* directory in your project.
<?xml version="1.0" encoding="utf-8"?>
 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent">
 
    <ImageView android:id="@+id/adapter_img"
               android:src="@drawable/ic_launcher"               android:layout_height="wrap_content"
               android:layout_width="wrap_content"/>
 
    <TextView android:id="@+id/adapter_tv"            android:layout_height="wrap_content"
            android:layout_width="wrap_content"/>
 
</LinearLayout>

  • Next in the constructor of the ArrayAdapter class specify the  custom layout resource and the id of the TextView element (adapter_tv) within it as arguments.

    Android ListView with custom layout

    ListView with custom layout

  • Bind the the adapter using the setListAdapter () method.
  • To track the user clicks like we did in the previous example, we need to get the reference to the TextView element that was clicked and append its Text to the ClickTracker. However this time, we get our custom layout as the View argument to  the onListItemClick () method instead of the actual TextView element.  So we use the findViewById () method to get the TextView element within it as shown below.
public class ListViewCustomLayout extends ListActivity {
   private TextView m_clickTracker;
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.listdemo);
      m_clickTracker = (TextView) findViewById(R.id.listdemo_tv1);
      String[] platforms = getResources().getStringArray(R.array.dev_platforms);
      ListAdapter listAdapter =
              new ArrayAdapter<String>(this,
                                      R.layout.img_text_adapter_view,                                      R.id.adapter_tv, platforms);      setListAdapter(listAdapter);   }
 
   @Override
   protected void onListItemClick(ListView l, View v, int position, long id) {
      StringBuilder text = new StringBuilder(m_clickTracker.getText());
      if (text.length() > 0) {
         text.append(", ");
      }
      TextView tv = (TextView) v.findViewById(R.id.adapter_tv);      text.append(tv.getText());
      m_clickTracker.setText(text.toString());
   }
}

Reusing Views


If you take a quick look into the internals of the ArrayAdapter’s getView () method, among other things you ‘ll find the following lines:
     
View view;
TextView text;
 
if(convertView==null){
        view=mInflater.inflate(resource,parent,false);
} else{
         view=convertView;
}
 
 // ...


The convertView shown above is the View object that is passed as one of the arguments to the getView() method. The view can be null sometimes  ( such as the first time its called) in which case a new view object is inflated ( i.e created)  using the Inflater class available in android. If its not null, the existing view is reused. This  usually happens when the user scrolls the list and the getView () method is called again for rendering the new set of  elements on the screen.  As a performance optimization, android automatically recycles the views of the rows that are no longer visible on the screen and uses them for rendering the currently viewable elements.  Its recommended to follow the same pattern if you are writing your own Adapters and inflating the views. The performance gain is significant when compared to creating new view objects each time.
Web Analytics