Create Custom Adapter in List View

Create Custom Adapter in List View thumbnail
59K
By Sanjeev K. Saroj 02 April, 2017

This article is about creating custom adapters for listview in android. Starting from what is an adapter, it explains about arrayadapter, cursoradapter along with how to create custom adapter for ListView in android application. It also explains about how to optimize listview using ViewHolder pattern.

What is an Adapter in Android

An Adapter object acts as a bridge between an AdapterView and the underlying data for that view. The Adapter provides access to the data items. The Adapter is also responsible for making a View for each item in the data set.

android-adapter
 Other Interesting Posts
Android Asynctask Example
Android Service Example
Broadcastreceiver Example Tutorial

What is an Array Adapter

ArrayAdapter links the array to the Adapter View. We use it when our data source in an array. The default ArrayAdapter converts an array item into a String object putting it into a TextView. The text view is then displayed in the AdapterView (a ListView for example).

When we create the adapter, we need to supply the layout for displaying each array string. We can define our own or use one of Android’s, such as : android.R.layout.simple_list_item_1. Following is an example to define an arrayAdapter.

   ArrayAdapter adapter = new ArrayAdapter
						(this, android.R.layout.simple_list_item_1, android.R.id.text1, here we pass String Array values);
   
 

Here the first parameter is context, second parameter is Xml Layout for the row and the third parameter is the id of the TextView within the layout resource to be populated and last parameter is the array containing values.Follow ArrayAdapter for more information on array adapter.

What is a CursorAdapter

We use cursorAdapter when we have data in Cursor e.g when we get data from database. With the use of cursor adapter we can have more control over the binding of data values to layout controls.

What is the Basic use of an Adapter

An Adapter object acts as a bridge between an AdapterView and the underlying data for that view. The Adapter provides access to the data items. The Adapter is also responsible for making a View for each item in the data set. Adapters are responsible for supplying the data and creating the views representing each item.

Lets suppose that if we want to display a list in android app for this we use ListView provided by android. Here ListView don't contain any data themselves. Its just a UI element without data in it. You can populate your ListViews by using an Android adapter.

Why we need Custom Adapter if Android Provides ArrayAdapter & CursorAdapter

Customadapter extends Baseadapter and it is very flexible i.e. it allows you to do pretty much whatever you want whereas ArrayAdapter is a more complete implementation that works well for data in arrays or ArrayLists. Similarly, there is a related CursorAdapter that you should use if your data is in a Cursor.BaseAdapter as its name implies, is the base class for so many concrete adapter implementations on Android. It is abstract and therefore, cannot be directly instantiated.

Steps to Create Custom Adapter in Android

1. Create a class Customadapter which extends BaseAdapter and implements abstact methods.

2. Create a model class for saving data.

3. Save model data in arralist for each row.

4. Create a Custom adapter class and pass Arraylist as a parameter in customadapter constructor.

Now let us start creating a custom adapter by defining the project structure first.

Project Structure

custom-adapter-project-strct

Following is the activity_list.xml. This xml contains listView.

activity_list.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.devglan.customadapter.ListViewActivity">

  <ListView
      android:id="@+id/list_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent"></ListView>
</RelativeLayout>

Following is the custom adapter for ListView that will display our custom ListView called ListViewActivity because this Activity is going to display the different options user can set to control the app. There are three list item types, one list item type has an ImageView and the second list item type has a TextViewImage name and the third list item type has a discription TextView.Create an object of CustomListAdapter and set adapter on listView.

ListViewActivity.java
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;

import java.util.ArrayList;

/**
 * Created by Sanjeev k Saroj on 28/2/17.
 */

public class ListViewActivity extends AppCompatActivity {

    ListView list_view;
    CustomListAdapter customListAdapter;
    ArrayList customListDataModelArrayList=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list);
        PopulateData();
        initView();
    }
	
    public void initView(){
        list_view = (ListView) findViewById(R.id.list_view);
        customListAdapter = new CustomListAdapter(ListViewActivity.this, customListDataModelArrayList);
        list_view.setAdapter(customListAdapter);
    }

    public void PopulateData(){

        for (int i=0;i<10;i++){

            CustomListDataModel customListDataModel = new CustomListDataModel();
            switch (i)
            {
                case 0:
		    customListDataModel.setImageName("Angry Bird Red");
		    customListDataModel.setImage_id(R.drawable.angry_bird);
		    customListDataModel.setImageDiscription("Angry Bird is red in color");
                    break;

                case 1:
                    customListDataModel.setImageName("Angry Bird Black");
                    customListDataModel.setImage_id(R.drawable.angrybird_black);
                    customListDataModel.setImageDiscription("Angry Bird is black in color");
                    break;

                case 2:
                    customListDataModel.setImageName("Angry Bird Blue");
                    customListDataModel.setImage_id(R.drawable.angrybird_blue);
                    customListDataModel.setImageDiscription("Angry Bird is blue in color");
                    break;

                case 3:
                    customListDataModel.setImageName("Angry Bird Red");
                    customListDataModel.setImage_id(R.drawable.angry_bird);
                    customListDataModel.setImageDiscription("Angry Bird is red in color");
                    break;

                case 4:
                    customListDataModel.setImageName("Angry Bird Black");
                    customListDataModel.setImage_id(R.drawable.angrybird_black);
                    customListDataModel.setImageDiscription("Angry Bird is black in color");
                    break;
                case 5:
                    customListDataModel.setImageName("Angry Bird Blue");
                    customListDataModel.setImage_id(R.drawable.angrybird_blue);
                    customListDataModel.setImageDiscription("Angry Bird is blue in color");
                    break;

                case 6:
                    customListDataModel.setImageName("Angry Bird Green");
                    customListDataModel.setImage_id(R.drawable.angrybird_green);
                    customListDataModel.setImageDiscription("Angry Bird is green in color");
                    break;

                case 7:
                    customListDataModel.setImageName("Angry Bird Yellow");
                    customListDataModel.setImage_id(R.drawable.angrybird_yellow);
                    customListDataModel.setImageDiscription("Angry Bird is yellow in color");
                    break;

                case 8:
                    customListDataModel.setImageName("Angry Bird White");
                    customListDataModel.setImage_id(R.drawable.angrybird_white);
                    customListDataModel.setImageDiscription("Angry Bird is white in color");
                    break;

                case 9:
                    customListDataModel.setImageName("Angry Bird Red");
                    customListDataModel.setImage_id(R.drawable.angry_bird);
                    customListDataModel.setImageDiscription("Angry Bird is white in color");
                    break;
            }
            customListDataModelArrayList.add(customListDataModel);

        }

    }
}

Following is the CustomListAdapter that extends BaseAdapter. BaseAdapter is an Abstract class so implements abstract method of this class.

1. The getCount() method returns the total number of items to be displayed in a list. It counts the value from arraylist size . For example if we have an list of elements in a array list and we have to display the items in a list view then we can count the total number of elements using the size function and then that integer value is returned by the function getCount() as shown below.

2. getView Method is called multiple time as the Size of Arralist contains.This method is automatically called when the list item view is ready to be displayed or about to be displayed. In this method we set layout for list item using Layoutinflater class and after that add data to View.

CustomListAdapter.java
package com.devglan.customadapter;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * Created by Sanjeev k Saroj on 28/2/17.
 */

public class CustomListAdapter extends BaseAdapter {

    Activity activity;
    ArrayList customListDataModelArrayList = new ArrayList<>();
    LayoutInflater layoutInflater = null;

    public CustomListAdapter(Activity activity, ArrayList customListDataModelArray){
        this.activity=activity;
        this.customListDataModelArrayList = customListDataModelArray;
        layoutInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    
    @Override
    public int getCount() {
        return customListDataModelArrayList.size();
    }

    @Override
    public Object getItem(int i) {
        return customListDataModelArrayList.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

	private static class ViewHolder{
		ImageView image_view;
		TextView tv_name,tv_discription;

	}
    ViewHolder viewHolder = null;


    // this method  is called each time for arraylist data size.
    @Override
    public View getView(int position, View view, ViewGroup viewGroup) {

        View vi=view;
        final int pos = position;
        if(vi == null){
		
            // create  viewholder object for list_rowcell View.
            viewHolder = new ViewHolder();
            // inflate list_rowcell for each row
            vi = layoutInflater.inflate(R.layout.list_rowcell,null);
            viewHolder.image_view = (ImageView) vi.findViewById(R.id.image_view);
            viewHolder.tv_name = (TextView) vi.findViewById(R.id.tv_name);
            viewHolder.tv_discription = (TextView) vi.findViewById(R.id.tv_discription);
            /*We can use setTag() and getTag() to set and get custom objects as per our requirement. 
            The setTag() method takes an argument of type Object, and getTag() returns an Object.*/
            vi.setTag(viewHolder);
        }else {

             /* We recycle a View that already exists */
           viewHolder= (ViewHolder) vi.getTag();
        }

        viewHolder.image_view.setImageResource(customListDataModelArrayList.get(pos).getImage_id());
        viewHolder.tv_name.setText(customListDataModelArrayList.get(pos).getImageName());
        viewHolder.tv_discription.setText(customListDataModelArrayList.get(pos).getImageDiscription());


        return vi;
    }
}

CustomListDataModel is the model class and contains the data we will save in the arralist and show in the user interface.

CustomListDataModel.java
package com.devglan.customadapter;

public class CustomListDataModel {
    private String ImageName="";
    private String ImageDiscription;
    private int Image_id;

    //getters and setters goes here
}

list_rowcell.xml
<?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">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/angry_bird"/>
    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Angry Bird"
        android:layout_below="@+id/image_view"
        android:padding="10dp"
        android:layout_marginLeft="20dp"/>
    <TextView
        android:id="@+id/tv_discription"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Discription"
        android:layout_toRightOf="@+id/image_view"
        android:layout_marginTop="30dp"
        android:layout_marginLeft="10dp"
        />
</RelativeLayout>

How to Optimise ListView using ViewHolder Pattern

Let's look at the getView() in CustomListAdapter class. When it is loaded for the first time vi is null. We need to inflate our list item layout and find the TextView, ImageView via findViewById(). Now The second time it was loaded, vi was not null, that means we don’t have to inflate it again. But we’ll use findViewById() again since we can now access the TextView, ImageView via its ViewHolder object. If getView() is called multiple times then at that time vi is not null. If findViewById() is constantly called, it will work but, it slows down the performance especially if you have lots of items and Views in your ListView.

Conclusion

I hope this article served you whatever you were looking for. If you have anything that you want to add or share then please share it below in the comment section.

Download source

Share

If You Appreciate This, You Can Consider:

We are thankful for your never ending support.

About The Author

author-image
Android Developer at Tech Mahindra

Further Reading on Android