ListView is one of the most common features implemented in any Android project. There are quite a few ways to implement ListView. The one we will be looking in today is a little on the advanced side and will help you make some zazzy Custom ListViews.
Before we begin, lets define a scenario and make sure we are all on the same page as far as the requirements are concerned.
We will have a data source (lets say some service like twitter), an array of objects (comments from the service) which we need to display in a list. The data source object would have
- User’s Image
- Name
- Comment
- A clickable link
There will be a single item type in the list. We will not include headers or footers in the list.
Before we begin, here are the components
- UI
- comment_list_row.xml: This is the layout of each of your List items.
- comment_list.xml: This is the Page containing your ListView.
- CommentListActivity.java: An activity derived from the Android Activity.
- Adapter
- CommentAdapter.java: An adapter derived from the Android ArrayAdapter.
Let us start with the UI components.
comment_list_row.xml
Make a simple UI containing all the fields mentioned above in the requirements. I generally prefer using RelativeLayout for basically 2 reasons. It gives me a lot more flexibility in laying out my components and at the same time does it efficiently.

comment_list.xml
Next we make the main layout which will house the ListView and will be set as the main content view in the CommentListActivity.java. Its a very simple xml with just a ListView item in a RelativeLayout. I have added 2 more TextViews, one to be displayed when the list is empty and the other is passed to the adapter. It is an empty textview which the adapter uses to display the data in case there is no valid view defined for the row.

CommentListActivity.java
This is our main activity or rather our only activity. We derive this from the Android Activity and override the onCreate() function. We get a reference to the ListView object using the findViewById() function and then set it’s adapter.
The adapter basically forms a bridge between the list and the underlying data. There are different types of adapters that can be used to supply data to the list but for now we will use a derivation of the ArrayAdapter. More about it later in the tutorial.
Tip!
To check that the provided view is shown when there is no data, comment out the prepareDataList() function.
We use the setEmptyView() function to set a view to display when there is no data to display in the list. The prepareDataList() function is used to generate the data source.
Set the ListView’s OnItemClickListener to handle the process that you may need to accomplish when your user clicks on an item.
[sourcecode language="java"]
public class CommentListActivity extends Activity {
private ArrayList<CommentObject> commentList = null;
private ListView commentListView = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.comment_list);
//Prepare the Dataset
prepareDataList();
commentListView = (ListView)findViewById(R.id.listComment);
TextView emptyList = (TextView)findViewById(R.id.txtEmptyList);
emptyList.setText("No comments to display!");
commentListView.setEmptyView(emptyList);
CommentArrayAdapter adapter = new CommentArrayAdapter(this, R.id.txtLoadingList, commentList);
commentListView.setAdapter(adapter);
//Manage the onItemClick method
commentListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
CommentObject currComment = (CommentObject)parent.getItemAtPosition(position);
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(CommentListActivity.this,
"You clicked on a comment by "+currComment.senderName, duration);
toast.show();
}
});
}
private void prepareDataList(){
/*
* Data for the list is loaded here
*/
}
}
[/sourcecode]
CommentAdapter.java
This is the heart of our list and needs close attention. If you master the adapter, you can customize your ListView as much as you want. In this tutorial, we will look into the ArrayAdapter. We start by overriding the following functions,
getCount() : Override this function to return the number of items present in the data set in the adapter. Here we return the size of the ArrayList containing the comment objects.
[sourcecode language="java" light="true"]
@Override
public int getCount() {
if( m_comments != null ){
return m_comments.size();
}
return 0;
}
[/sourcecode]
getView(int position, View convertView, ViewGroup parent) : This function is used to prepare the view that presents the data at the specified position in the data set. Here we inflate the view from the comment_list_row.xml and then bind the data in the ArrayList at the index corresponding to the position value. You will observe that we do a null check for the convertView and create only if it is null. This helps in making it more efficient as the xml inflation is not done for every row.
You need to implement the onClickListener of your link’s TextView to handle it.
[sourcecode language="java" light="true"]
@Override
public View getView(int position, View convertView, ViewGroup parent) {
CommentViewHolder holder = null;
//form the view
if( convertView == null ){
holder = new CommentViewHolder();
convertView = m_inflater.inflate(R.layout.comment_list_row, parent, false);
holder.senderImage = (ImageView)convertView.findViewById(R.id.imgUserImage);
holder.senderName = (TextView)convertView.findViewById(R.id.txtUserName);
holder.commentText = (TextView)convertView.findViewById(R.id.txtUserComment);
holder.link = (TextView)convertView.findViewById(R.id.txtClickableLink);
convertView.setTag(holder);
}else{
holder = (CommentViewHolder)convertView.getTag();
}
//bind the data to the view
CommentObject comment = m_comments.get(position);
if( comment.senderPhoto.contentEquals("calvin.png") )
holder.senderImage.setImageResource(R.drawable.calvin);
else if( comment.senderPhoto.contentEquals("hobbes.png") )
holder.senderImage.setImageResource(R.drawable.hobbes);
else if( comment.senderPhoto.contentEquals("susie.png") )
holder.senderImage.setImageResource(R.drawable.susie);
holder.senderName.setText(comment.senderName);
holder.commentText.setText(comment.commentText);
final String clickableText = comment.link;
holder.link.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(m_context, clickableText, duration);
toast.show();
}
});
return convertView;
}
[/sourcecode]
ViewHolder Class : The ViewHolder class is used to make the View creation optimization that we just saw above. This class helps us create the View once and then stores it so that it can be re-used. In more advanced tutorials, you’ll observe how this class can be used to update the ListView dynamically.
[sourcecode language="java" light="true"]
private class CommentViewHolder{
ImageView senderImage;
TextView senderName;
TextView commentText;
TextView link;
}
[/sourcecode]
Screenshots

ListView without data

ListView with data
Final Review
In this tutorial you have learnt,
- Make a ListView and attach an ArrayAdapter to provide data to it.
- Handle both item clicks and also any clickable link that may be present in the item.
- Customize getCount() and getView() to make your own list item view.
- Use a ViewHolder to speed up your list creation.
You can find the source code attached Here.