Android Series: Custom ListView items and adapters
Posted by admin | Posted in Mobile Development | Posted on 20-05-2009
249
This is a short tutorial on how to populate your android list view, with data downloaded from the internet or other sources, using ArrayAdapter. ListView items view is declared in a separate XML file and displayed using custom adapter class.
First things first, so go ahead and create a new project using Eclipse equipped with ADT plugin.
The project described below assumes you have a list of objects created, this can be either downloaded from the internet as XML and parsed to create ArrayList of your custom objects or anything you imagine. I will not go into details on this tutorial how to create such an ArrayList but your imagination is the limit. Parsing XML downloaded from the net will be covered in the next tutorial coming up soon.
Click File -> New -> Project and select the ‘Android Project’ wizard:
Click next and fill out the next screen with the following values:
Once you have filled out all the necessary data you can click finish.
Your new project has just been created. Now lets modify it a bit to display our custom made list.
Open up SoftwarePassionView.java in the eclipse editor and change the class file to the following:
1. Define necessary member variables we will use later in our class
private ArrayList<Order> m_orders = null;
private OrderAdapter m_adapter;
private Runnable viewOrders;
m_ProgressDialog is a small pop up displaying information that your data is being downloaded or retrieved other way.
m_orders is an ArrayList which will hold our data downloaded from the internet or acquired other way
m_adapter is our custom class extending ArrayAdapter
viewOrders is a runnable for downloading data from the internet in a separate thread
To import whatever you can at this point click Ctrl+Shift+O, some classes like Order or OrderAdapter are not created yet but don’t worry we will come to that point soon.
Another important note at this point is that your SoftwarePassoinView should extend ListActivity instead of simple Activity.
Your class should look more or less something like this now:
import java.util.ArrayList;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.os.Bundle;
public class SoftwarePassionView extends ListActivity{
private ProgressDialog m_ProgressDialog = null;
private ArrayList<Order> m_orders = null;
private OrderAdapter m_adapter;
private Runnable viewOrders;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Now lets create our simple Order class holding single order.
Right click on the project and and select ‘New’ -> ‘Class’, name it order and open it up in the editor.
The source code for our orders looks like this:
public class Order {
private String orderName;
private String orderStatus;
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public String getOrderStatus() {
return orderStatus;
}
public void setOrderStatus(String orderStatus) {
this.orderStatus = orderStatus;
}
}
The Order class is very simple and contains only 2 strings with getters and setter generated for them
Now lets change our main.xml file to hold our custom list items:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
<TextView
android:id="@+id/android:empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="@string/main_no_items"/>
</LinearLayout>
This layout will display our list items if any and if the list is empty it will display ‘No orders to display’ string defined in string.xml resource file.
<resources>
<string name="hello">Hello World, SoftwarePassionView!</string>
<string name="app_name">Software Passion</string>
<string name="main_no_items">No orders to display</string>
</resources>
Our list item (single row on the list) have a custom layout as well, defined in row.xml file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginRight="6dip"
android:src="@drawable/icon" />
<LinearLayout
android:orientation="vertical"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="fill_parent">
<TextView
android:id="@+id/toptext"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center_vertical"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:id="@+id/bottomtext"
android:singleLine="true"
android:ellipsize="marquee"
/>
</LinearLayout>
</LinearLayout>
Single row example has been borrowed from the romain Guy website here
Ok, so we have all our layouts defined in the res folder under layout. Now its time to go back to our code and create our custom OrderAdapter class which will manage our list of orders:
private ArrayList<Order> items;
public OrderAdapter(Context context, int textViewResourceId, ArrayList<Order> items) {
super(context, textViewResourceId, items);
this.items = items;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
}
Order o = items.get(position);
if (o != null) {
TextView tt = (TextView) v.findViewById(R.id.toptext);
TextView bt = (TextView) v.findViewById(R.id.bottomtext);
if (tt != null) {
tt.setText("Name: "+o.getOrderName()); }
if(bt != null){
bt.setText("Status: "+ o.getOrderStatus());
}
}
return v;
}
}
This is a private class and should be added to our SoftwarePassionView. This is extended ListAdapter which inside overriden getView method returns our row with assigned string values to the textfields defined in row.xml.
A huge part of our application is already done. Now we have to add some modifications to the onCreate method to initialize everything properly and add a method retrieving our orders from somewhere, lets start with the latter:
try{
m_orders = new ArrayList<Order>();
Order o1 = new Order();
o1.setOrderName("SF services");
o1.setOrderStatus("Pending");
Order o2 = new Order();
o2.setOrderName("SF Advertisement");
o2.setOrderStatus("Completed");
m_orders.add(o1);
m_orders.add(o2);
Thread.sleep(2000);
Log.i("ARRAY", ""+ m_orders.size());
} catch (Exception e) {
Log.e("BACKGROUND_PROC", e.getMessage());
}
runOnUiThread(returnRes);
}
Instead of creating our simple orders in the method above you could of course download them from somewhere and assign the result to the m_orders array list. The method runOnUIThread is a utility method for running tasks back on the main UI thread after the job is done on the separate thread created for long running tasks. We will call our getOrders method from a separate thread.
The returnRes runnable adds newly retrieved Order object to our custom Adapter and notifies it of the data change:
Now lets move to our overriden onCreate method. We will initialize here all the member variables as well as start a new thread retrieving our orders:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
m_orders = new ArrayList<Order>();
this.m_adapter = new OrderAdapter(this, R.layout.row, m_orders);
setListAdapter(this.m_adapter);
viewOrders = new Runnable(){
@Override
public void run() {
getOrders();
}
};
Thread thread = new Thread(null, viewOrders, "MagentoBackground");
thread.start();
m_ProgressDialog = ProgressDialog.show(SoftwarePassionView.this,
"Please wait...", "Retrieving data ...", true);
}
After initialization, we start new thread using the viewOrders runnable and show the progress dialog which we close once the orders are retrieved.
Now you should be able to run your application. After the application starts it spawns new thread and displays the loader:
![]() |
![]() |
And thats it. You can add an Item Click Listener to your list to start new activities etc.
Full source code for the SoftwarePassionView below:
import java.util.ArrayList;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class SoftwarePassionView extends ListActivity{
private ProgressDialog m_ProgressDialog = null;
private ArrayList<Order> m_orders = null;
private OrderAdapter m_adapter;
private Runnable viewOrders;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
m_orders = new ArrayList<Order>();
this.m_adapter = new OrderAdapter(this, R.layout.row, m_orders);
setListAdapter(this.m_adapter);
viewOrders = new Runnable(){
@Override
public void run() {
getOrders();
}
};
Thread thread = new Thread(null, viewOrders, "MagentoBackground");
thread.start();
m_ProgressDialog = ProgressDialog.show(SoftwarePassionView.this,
"Please wait...", "Retrieving data ...", true);
}
private Runnable returnRes = new Runnable() {
@Override
public void run() {
if(m_orders != null && m_orders.size() > 0){
m_adapter.notifyDataSetChanged();
for(int i=0;i<m_orders.size();i++)
m_adapter.add(m_orders.get(i));
}
m_ProgressDialog.dismiss();
m_adapter.notifyDataSetChanged();
}
};
private void getOrders(){
try{
m_orders = new ArrayList<Order>();
Order o1 = new Order();
o1.setOrderName("SF services");
o1.setOrderStatus("Pending");
Order o2 = new Order();
o2.setOrderName("SF Advertisement");
o2.setOrderStatus("Completed");
m_orders.add(o1);
m_orders.add(o2);
Thread.sleep(5000);
Log.i("ARRAY", ""+ m_orders.size());
} catch (Exception e) {
Log.e("BACKGROUND_PROC", e.getMessage());
}
runOnUiThread(returnRes);
}
private class OrderAdapter extends ArrayAdapter<Order> {
private ArrayList<Order> items;
public OrderAdapter(Context context, int textViewResourceId, ArrayList<Order> items) {
super(context, textViewResourceId, items);
this.items = items;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
}
Order o = items.get(position);
if (o != null) {
TextView tt = (TextView) v.findViewById(R.id.toptext);
TextView bt = (TextView) v.findViewById(R.id.bottomtext);
if (tt != null) {
tt.setText("Name: "+o.getOrderName()); }
if(bt != null){
bt.setText("Status: "+ o.getOrderStatus());
}
}
return v;
}
}
}
Enjoy!






Great tutorial.
Did you ever get around to doing a tutorial on a more-robust getOrders() method? Maybe one that reads from XML or pulls via http?
That would be awesome if you did.
well, look at my other posts about parsing JSON data and executing POST/GET requests, combine them togheter and you will get an answer
Two notes on this.
1. getSystemService(…) does not exist in ArrayAdapter. You need to change it to (LayoutInflater)getContext().getSystemService(…
2. It is not necessary to create a new list in copy all of those items into a new list in your getOrders function, nor do you need to have the loop in your returnRes function. You’ve already passed the m_orders list into the ArrayAdapter (by reference), so when you notify the adapter that the list has changed, it is able to access the list you just added stuff to.
Thanks for the code…it really helped me to get started. I am new to both Java and Android…started doing some Silverlight DEV 6 months a go.
Question on a piece of your code. What exactly does this do? I am still trying to understand how the structure of android views work.
Thanks
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
}
Have a look here: http://developer.android.com/reference/android/view/LayoutInflater.html
I can understand how the code works more or less. but i have a question about getView() method. I got a book showing something like your code, it’s just that it doesn’t explain well when the convertView might have null or non-null value. Plus I don’t get when this method is called. I break-pointed on this method with 3 elements in a normal array string and saw that this method was called 6 times, with convertView shifting from non-null to null value on every call. thanks for the help in advance!!!
Hey! Thank you for this very helpfull code snip. My question is now: How can i get the TextView Views out of the Listview over a onItemCLickListener….. im not able to do this.. please help me!.. i need the text view because i have to change the textstyle in the textview (which is in our listview) after clicking on it..
I am a beginner in Java and Android
I put OrderAdapter to a separate file and I get this:
Illegal modifier for the class OrderAdapter; only public, abstract & final are permitted
What should I do?
It had to be changed to public as I want to use it from a different class.
Hi. I am struggeling with
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Eclipse always tells me: method getSystemService(String) is undefinied for type OrderAdapter
What am I doing wrong?
Hallo.
I want to put a RadioGroup, which has 4 RadioButtons as Children, in each Row.
Now i can click on the RadioButtons with no Problem, but if i scroll the ListView, my selection is gone. I habe tried several days, but still i can not fix the problem.
Can anybody help?
I’m struggling to grasp where and how exactly I can attach an onItemClickListener. Is it to the adapter (m_adapter) and if so at which point? Does the update/runnable affect this too?
Great article by the way.
Hello, my application still has errors though the code doesn’t show any. It says that my application has stopped unexpectedly. Please help me out!
I’m a super beginner in android and your code really helps me out!
THANKS. You can email me too.
Can you continue using this code, whereby its clickable and goes to another page?
To add onItemClickListener:
1) Add this:
private OnItemClickListener listlistener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View arg1, int position,
long arg3) {
Toast.makeText(getApplicationContext(), “You have clicked on ” + ((Order)parent.getItemAtPosition(position)).getOrderName(), Toast.LENGTH_SHORT).show();
}
};
2) Then add this to the OnCreate after setContentView:
getListView().setOnItemClickListener(listlistener);
Can you continue using this code, whereby its clickable and goes to another page?
or read the data from website and show in listView ?
Great post !
But how and where do you say to the progress dialog to shutdown ?
[...] Software Passion: Android Series: Custom ListView items and adapters [...]
Thanks man!
Just wanted to say that your tutorial was GREAT
it helped me alot with my android project.
So THANKS!
Brgds Robert
it is possibile to show a different icon for different type of item in list? thanks
Hey Anon, what you mean by Step 2?
2) Then add this to the OnCreate after setContentView:
getListView().setOnItemClickListener(listlistener);
Omg thanks for the OnItemClick code Anon. But it doesn’t work!
HELP! Can’t toast didn’t appear!!!!
If i dont want to use the hard code for the data. I wanna take it out from my data base.
does this means i need nt the order class? and the arraylist?
Is it possible to get data from my database and set the text as from my data? so does this means I do not need the Order class? and the adapters?
Hi there! Your code works fine already and the onclicklistener too! :>
But now I’m kinda stuck, hope you guys help me out!!!!
I want everything above, the progress dialog and the listview. However, I wanna use my own data from my database. Help anyone? Cause I can’t solve this problem.
Is it possible to show another list in a list item ?
Hi, I’m having a trouble with this, how can i put data in 2 different listview? When i try to implement this, my listview content is exactly the same, and before i add new data i declare new adapter, and the result is both listview contains the same data which is combination of data from each listview. Thanks for your help, i really appreciate it a lot.
Hi,
Nice article.
How can i set single choice mode for custom listview ?.
This is a great tutorial. At first i was a bit taken that there was soo much code, but once i read through it and implemented it, it works great. Thanks so much for the help.
Admin : thanks a ton for this……successfully implemented the same functionality to my project……Kudos to u
Jyahao : What is the Error?
Inside the adapter use custom views.
If u use custom view with x items inside like textviews image views and many other view object u culd replace this 2 calls to findviewbyid to just one call to get the custom view by id and then refer to the n itmes in the custom view.
So instead n calls you just need one call.
TextView tt = (TextView) v.findViewById(R.id.toptext);
TextView bt = (TextView) v.findViewById(R.id.bottomtext);
I tried the exact same code, without any changes and it didn’t work.
What could be the possible problem? The screen after the ProgressDialog (in the background show empty text) shows a empty screen?!…
Now log for error. Any idea? I tried removing the thread and doing all process in same thread, still no result?
Excellent sample to get folks new to Android started. The ListView is one of those things that you would use again and again. Great service! Thanks!
[...] ListViews are fairly common, I suggest following this tutorial for your second Android app: Android Series: Custom ListView items and adapters | Software Passion Leverage these forums and others (sorry mods?). There are people willing to assist so long as you [...]
thanks for the helpful walkthrough!!
Just what I needed! Thanks.
But, please, repair the code where getSystemService() call.
Hi,
i want to display admob or tab in the button of this custum listview ,i tried but not got any success,any help for displaying admob.
Great tutorial!! I’m trying to adapter this to a Spinner widget and when I try to select the spinner, i get “java.lang.IllegalStateException: ArrayAdapter requires the resource ID to be a TextView”. The resource ID I’m using is R.layout.row (the same as the tutorial). The XML says it’s parent node is a LinearLayout so maybe that’s my problem? If so, I’m stumped because I was hoping to control positions with LinearLayout. If anyone has got this working I’d appreciate any input.
This got me the rest of the way implementing this with a spinner
…
http://stackoverflow.com/questions/3072147/how-to-correctly-overwrite-methods-of-spinneradapter
[...] You need to manage the data stored in each row in the adapter. When a list item is not visible, it is destroyed. The getView function gets called for every list item once it appears on screen. When you scroll and it goes off screen, it is destroyed and the process starts again. If you want the data to persist, you need to manage it behind the scenes. Here's a good tutorial where an object called Order is created and each row in the list represents an Order. The tutorial writer uses an ArrayList in an extended Adapter to hold the Orders for all rows. The getView grabs the order corresponding to that position and draws the information. In your case, upon clicking on the row, you would update the items Order array to persist the data. Android Series: Custom ListView items and adapters | Software Passion [...]
Please help me on this, I want have listview of short sentences in my app. These sentences are stored in a xyz.xml resource file as string array items. What confuses me is the layout xml file. Everywhere I read some tutorials have both ListView and TextView tags and some have one of them. So I am not sure why they use either one. Also, how to use ArrayAdapter to place the sentences into the listview.
Please help, I just started this journey.
Thank you very much.. Exactly what I was looking for..
Like this!
Thanks for great tutorial.
Excellent tutorial! Can you follow up with a part-2 on how to implement the Item Click Listener?
In getOrders I wanted to grab data from a db and found creating new Order objects redundant o1, 02 so I modified the code to be:
Order o1 = new Order();
for(…)
o1.setOrderName(“[name from db]“);
o1.setOrderStatus(“[status from db]“);
m_orders.add(o1);
o1 = new Order();
} //for
I was surprised that o1 had to have the “new Order()” but I guess it gets saved by reference of some sort. Without it all items have the value of the last item in the database.
that’s great!!
thank a lot..
I browsed it , but now I will practise it.
Good example…easy to follow…saved me trying to figure it out. Thanks!
Thanks for a good code.
thanks alot, ur row xml was my first of my custom list.
everythings r fine, but now i have added a button in the list but the listener is not at al listening to the clicks. wher m i going wrong, is there nything that i need to do..
thanks.