Listview getViewType() and getViewTypeCount() in Action

This  is an article on listview with different view’s.

We all know that listview is the most used and conventional way of displaying list  of data in android. Many-a-times we do encounter a scenario where we want to display list item depending on a specific condition for example have a look at the images below.

The common way of displaying such a data is to inflate one row and depending on the condition you may hide or make a view visible.

Toggling a view between VIEW.GONE and VIEW.VISIBLE can be a very expensive task inside the getview(..) which will sure affect the list scroll. This can be easily managed and tackled with listview’s pre-defined methods getViewTypeCount() and getItemViewType(..).

So to begin with you need to create separate layouts for each type of view that will be displayed. This way it will be more efficient and less clustered to manage the data.

To put all this into action i have created a demo project which can be downloaded here.

In this project i ‘ m showing 3 different types of row in a listview:

1. A simple text

2. Text with image view

3. Poll with three option

so first create 3 different xmls for different row type.

  • view_row_type_one.xml (for text layout)
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/textview"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_gravity="center"
 android:background="@android:color/darker_gray"
 android:textColor="@android:color/black"
 android:textSize="20sp"
 android:padding="10dp"/>

  • view_row_type_two.xml (layout with text and image )
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@android:color/darker_gray"
 android:padding="10dp" >

<ImageView
 android:id="@+id/imageView"
 android:layout_width="100dp"
 android:layout_height="100dp"
 android:layout_centerInParent="true"
 android:layout_marginBottom="10dp"
 android:contentDescription="@null" />

<TextView
 android:id="@+id/labelTextView"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_alignEnd="@id/imageView"
 android:layout_below="@id/imageView"
 android:layout_marginTop="15dp"
 android:textColor="@android:color/black"
 android:textSize="20sp" />

</RelativeLayout>

* view_row_type_three.xml (layout with radio buttons)

<?xml version="1.0" encoding="utf-8"?>
<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@android:color/darker_gray"
 android:padding="10dp" >

<TextView
 android:id="@+id/questionTextView"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginLeft="5dp"
 android:textColor="@android:color/black"
 android:textSize="20sp" />

<RadioButton
 android:id="@+id/radioButtonOne"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="@string/yes"
 android:textColor="@android:color/black"
 android:textSize="20sp" />

<RadioButton
 android:id="@+id/radioButtonTwo"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="@string/no"
 android:textColor="@android:color/black"
 android:textSize="20sp" />

<RadioButton
 android:id="@+id/radioButtonThree"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="@string/cant_say"
 android:textColor="@android:color/black"
 android:textSize="20sp" />

</RadioGroup>

What does getViewTypeCount() and getItemViewType(…) do ?

These methods are called before getView(…).

1] getViewTypeCount()

Returns the count of different type of views. Here we are having three different type of views so this method will return count as 3.

2] getItemViewType(…) 

Here we will write the logic to determine the type of view.

@Override

public int getItemViewType(int position) {

if(mList.get(position) instanceof DataModel){

return VIEW_TYPE_TEXT;

}else if(mList.get(position) instanceof ImageModel){

return VIEW_TYPE_IMAGE;

}else{

return VIEW_TYPE_QUESTION;
}

Inside getView(…) method first we determine the type of view by calling getItemViewType(..) method, this will return the type to be inflated as shown below.

@Override

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

ViewHolder.DataViewHolder dataViewHolder = null;

ViewHolder.ImageViewHolder imageViewHolder = null;

ViewHolder.QuestionViewHolder questionViewHolder = null;

int type = getItemViewType(position); // to determine type of view.

if(type == VIEW_TYPE_TEXT){

if(convertView == null){

convertView = mInflater.inflate(R.layout.view_row_type_one, parent, false);

convertView.setTag(dataViewHolder);

.................

}else{

dataViewHolder = (DataViewHolder)convertView.getTag();

........

}

}else if(type == VIEW_TYPE_IMAGE){

if(convertView == null){

convertView = mInflater.inflate(R.layout.view_row_type_two, parent, false);

convertView.setTag(imageViewHolder);

..........

}else{

imageViewHolder = (ImageViewHolder)convertView.getTag();

...............

}

}else{

if(convertView == null){

convertView = mInflater.inflate(R.layout.view_row_type_three, parent, false);

convertView.setTag(questionViewHolder);

.................

}else{

questionViewHolder = (ViewHolder.QuestionViewHolder)convertView.getTag();

.......

}

}

return convertView;

}

This is all it. You can follow this mechanism of displaying data and you will notice significant improvements in the list scroll and the number of objects created. Hope this is useful to someone.

Download sample project from here.

Happy coding, happy learning. 🙂

Advertisements

3 thoughts on “Listview getViewType() and getViewTypeCount() in Action

  1. Pulled your source. Nice tutorial. A couple of questions:
    1. Why not null your other viewholder objects 1 time at the beginning or end of your switch-case statements rather than in each 1/2 of the if-then-else block?
    2. You’re creating a field for your inflater. Is there a reason you’re doing that rather than using ((Activity) context).getLayoutInflater() (or similar)?

    I made those adjustments as well as a ViewHolder adjustment I prefer. They can be seen here (http://pastebin.com/U8SZrZUe). I’d like your feedback.

    Regards,

    Bill

    Like

    • Hi Bill,

      Thanks for your valuable insight on the article. Your suggestions are good but we don’t think so it would make much difference. If you notice any improvements in the benchmark do reply we will update the code.

      Like

      • As I said previously, it’s a nice tutorial. As such you should strive to give your users the most sound solution possible. The items I mentioned simply improve the design of what you provided and have nothing to do with performance.

        Lifting the null ViewHolder statements out of the if-block makes the actual work to be done based on the if-then-else statement cleaner and nulling those values is a good idea anyway.

        Minimizing fields to those things that are absolutely necessary should be something we all strive to do. Is it easier to just slap variables into class member variables? Yep. Every new programmer does it. Even the latest build tools will give you a Lint warning that your variable could be made local.

        The ViewHolder pattern I used, shown in the pastebin, is purely a preference, but it does help ensure those that use your tutorial will abstract the costly findViewById() call away from their getView() method and minimize mistakes.

        Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s