logo

1. Android and Lists

ListView
Android provides the view ListView which is capable of displaying a scrollable list of items.

ListActivity
An activity that displays a list of items by binding to a data source such as an array or Cursor, and exposes event handlers when the user selects an item.

You can directly use the ListView in your layout as any other user interface component.
ListActivity extends Activity and provides simplified handling of lists. For example you have a predefine method if someone clicks on a list element.

ListActivity contains

a ListAdapter which is responsible for managing the data. This adapter must be set in the onCreate() method of your Activity via the setListAdapter() method.

If the user select in the list a list entry the onListItemClick() method will be called. This method allows to access the selected element.

Android provides already some default layouts which you can use in your Adapter, e.g. android.R.layout.simple_list_item1. In case you don’t want to use one of the pre-defined layouts your own layout must have an ListView element with the android:id attribute set to @+android:id/list. For example:

<ListView
  android:id="@+android:id/list"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" >
</ListView>

You can also use a view with the id @android:id/empty. This view is displayed if the list is empty. For example you could display here an error message.

2. Adapter

a) What are Adapters?
ListView gets the data to display via an adapter. Well adapter in android are basically bridge between UI components and the datasource that fill data into UI Component.

Android has two standard adapters, ArrayAdapter and CursorAdapter. ArrayAdapter can handle data based on Arrays or Lists while SimpleCursorAdapter handle database related data. You can develop your own Adapter by extending these classes or the BaseAdapter class.

3. Tutorial: Simple ListActivity

In this, we will create an extremely simple list based on some default provides by Android. We use the default Adapter class “ArrayAdapter” and a layout which is predefined by Android.

Create a new Android project “com.mobisys.android.t_simplelistactivity” with the activity “MyListActivity“. You do not need to change the default layout “main.xml“. Create the following activity.

package com.mobisys.android.t_simplelistactivity;
import android.app.Activity;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

public class MyListActivity extends ListActivity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.main);
        String[] values=new String[]{"Apple", "Samsung", "Nokia", "iOS", "Android", "Symbian"};
        ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,values);
        setListAdapter(adapter);
    }
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id)
    {
    	String item=(String)getListAdapter().getItem(position);
    	Toast.makeText(this,item+" Selected",Toast.LENGTH_SHORT).show();
    }
}

Note that we do not use the setContentView(). An ListActivity has per default a ListView available if you do not specify a layout which should be used.

Run the application & select any of the list item

4. Tutorial: ListActivity with own layout

You can also define your own layout for the rows and assign this layout to your adapter. If you do this the layout will be the same for every entry.In our example we will add a fixed icon to each list entry.

Create a new Android project “com.mobisys.android.t_own_layout_list_activity” with the activity “MyListActivity” then
Create the following layout file “rowlayout.xml” in the res/layout folder of your project “com.mobisys.android.t_own_layout_list_activity“.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
  <Imageview android:id="@+id/icon"
    android:layout_width="22px"
    android:layout_height="22px"
    android:layout_marginLeft="4px"
    android:layout_marginRight="10px"
    android:layout_marginTop="4px"
    android:src="@drawable/icon">
  </Imageview>
    
  <TextView
    android:id="@+id/label"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@+id/label"
    android:textSize="20px" >
    </TextView>  
</LinearLayout>

Change your MyListActivity class to the following. This is almost the same coding as in the previous example, the only difference is that we are using our own layout in the ArrayAdapter and telling the adapter which UI element should contains the text.

package com.mobisys.android.t_own_layout_list_activity;

import android.app.Activity;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

public class MyListActivity extends ListActivity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        String[] values = new String[] { "Apple", "Samsung", "Nokia",
				"Moto", "iOS", "Android", "Symbian", "mata",
				"Mos", "2.3Os" };
		// Use your own layout
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
				R.layout.rowlayout, R.id.label, values);
		setListAdapter(adapter);
	}

	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		String item = (String) getListAdapter().getItem(position);
		Toast.makeText(this, item + " selected", Toast.LENGTH_LONG).show();
	}
 }

Run the application and select any of the list item

5. Implementing your own ListAdapter

If you want to use different layouts based on in row data you must implement your own adapter for the ListView. You would implement BaseAdapter or could extend an existing adapter like ArrayAdapter. In your implementation you would at least override the getView() method.
This method is responsible for creating the individual rows of your ListView. The getView() method returns a View for each row. .

This View is typically a Layout ( ViewGroup ) and contains several other Views, e.g. an ImageView and a TextView.

Within the getView() method you would typically inflate an XML based layout and then set the values of the individual Views in the layout based on the data for the row. The individual elements in the layout can be found via the findViewById() method call.

To read an layout from an XML resource in the getView() method you can use the system service LayoutInflator. This service can get accessed via the Activity or via the context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); method call.

6. Tutorial: Implementing your own adapter

Defining a simple Adapter
In this example we extend ArrayAdapter but we could also directly implement BaseAdapter

The following uses two images “no.png” and “ok.png“. I placed it in the “res/drawable” folder. You must create your own icons. In case you don’t find any icons just copy “icon.png” and use a drawing program to change it a little bit.

Create a new Android project “com.mobisys.android.t_own_listadapter” with the activity “MyListActivity” then
Create Layout file “rowlayout.xml” in the res/layout folder & that will remain same as defined above tutorial.
Create the class MySimpleArrayAdapter which will serve as our adapter.

 
package com.mobisys.android.t_own_listadapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class MySimpleArrayAdapter extends ArrayAdapter<String> {
	private final Context context;
	private final String[] values;

	public MySimpleArrayAdapter(Context context, String[] values) {
		super(context, R.layout.rowlayout, values);
		this.context = context;
		this.values = values;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		LayoutInflater inflater = (LayoutInflater) context
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		View rowView = inflater.inflate(R.layout.rowlayout, parent, false);
		TextView textView = (TextView) rowView.findViewById(R.id.label);
		ImageView imageView = (ImageView) rowView.findViewById(R.id.icon);
		textView.setText(values[position]);
		// Change the icon for Windows and iPhone
		String s = values[position];
		if (s.startsWith("Symbian") || s.startsWith("iOS")
				|| s.startsWith("Apple")) {
			imageView.setImageResource(R.drawable.no);
		} else {
			imageView.setImageResource(R.drawable.ok);
		}

		return rowView;
	}
}

To use this adapter, change the class “MyListActivity” to the following.

 
package com.mobisys.android.t_own_listadapter;


import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;

import android.widget.ListView;
import android.widget.Toast;

public class MyListActivity extends ListActivity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        String[] values = new String[] { "Apple", "Samsung", "Nokia",
				"Moto", "iOS", "Android", "Symbian", "mata",
				"Mos", "2.3Os" };
		// Use your own layout
        MySimpleArrayAdapter adapter = new MySimpleArrayAdapter(this, values);
		
		setListAdapter(adapter);
	}

	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		String item = (String) getListAdapter().getItem(position);
		Toast.makeText(this, item + " selected", Toast.LENGTH_LONG).show();
	}
 }

If you run this example you should get a list with different icons for the certain elements.

7. Performance Optimization

Every View which get inflated from the XML resources will result in a Java object. Creating Java objects is expensive with regards to time and memory consumption.

Not all rows are displayed at the same time, therefore Android recycles rows ( Views ) which are not displayed anymore and allows that these rows are reused. If it has a recycled row it passes these rows to getView() method as convertView parameter.

Your adapter implementation can re-use this view and can avoid inflating a layout for the current row. This saves memory and CPU consumption. It just need to set the new values into the existing layout.

convertView may be NULL if there is no row to recycle, your implementation need to check this.

Tutorial for Performance Optimization

Create a new Android project “com.mobisys.android.t_perform_optimize” with the activity “MyListActivity” then
Create Layout file “rowlayout.xml” in the res/layout folder & that will remain same as defined above tutorial.
Create the class MyPerformanceArrayAdapter which will serve as our adapter.

package com.mobisys.android.t_perform_optimize;


import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class MyPerformanceArrayAdapter extends ArrayAdapter<String> {
	private final Activity context;
	private final String[] names;

	public MyPerformanceArrayAdapter(Activity context, String[] names) {
		super(context, R.layout.rowlayout, names);
		this.context = context;
		this.names = names;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		
		View rowView=convertView;
		if(rowView==null){
		LayoutInflater inflater = context.getLayoutInflater();
		 rowView= inflater.inflate(R.layout.rowlayout, parent, false);
		}
		TextView textView = (TextView) rowView.findViewById(R.id.label);
		ImageView imageView = (ImageView) rowView.findViewById(R.id.icon);
		String s = names[position];
		textView.setText(s);
		if (s.startsWith("Apple") || s.startsWith("Nokia")
				|| s.startsWith("iOS") || s.startsWith("Mos")) {

			imageView.setImageResource(R.drawable.no);
		} else {
			imageView.setImageResource(R.drawable.ok);
		}

		return rowView;
	}
}

and MyListActovity class will contain:

package com.mobisys.android.t_perform_optimize;

import android.app.Activity;
import android.os.Bundle;

import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.Toast;

public class MyListActivity extends ListActivity {
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		String[] values = new String[] { "Apple", "Samsung", "Nokia",
				"Moto", "iOS", "Android", "Symbian", "mata",
				"Mos", "2.3Os" ,"WebOS", "Ubuntu", "Windows7", "Max OS X",
				"Linux", "OS/2"};
		setListAdapter(new MyPerformanceArrayAdapter(this, values));
	}

	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		String item = (String) getListAdapter().getItem(position);
		Toast.makeText(this, item + " selected", Toast.LENGTH_LONG).show();
	}
}

Run the application

8. SimpleCursorAdapter

In case you work with a content provider or directly with the database you can use the SimpleCursorAdapter to define the data for your ListView

Create a new Android project “com.mobisys.android.t_demo_cursor” with the activity “MyListActivity“. Create the following activity.

import android.app.ListActivity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.ListAdapter;
import android.widget.SimpleCursorAdapter;

public class MyListActivity extends ListActivity {
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Cursor mCursor = getContacts();
		startManagingCursor(mCursor);
		// Now create a new list adapter bound to the cursor.
		// SimpleListAdapter is designed for binding to a Cursor.
		ListAdapter adapter = new SimpleCursorAdapter(this, // Context.
				android.R.layout.two_line_list_item, // Specify the row template
														// to use (here, two
														// columns bound to the
														// two retrieved cursor
														// rows).
				mCursor, // Pass in the cursor to bind to.
				// Array of cursor columns to bind to.
				new String[] { ContactsContract.Contacts._ID,
						ContactsContract.Contacts.DISPLAY_NAME },
				// Parallel array of which template objects to bind to those
				// columns.
				new int[] { android.R.id.text1, android.R.id.text2 });

		// Bind to our new adapter.
		setListAdapter(adapter);
	}

	private Cursor getContacts() {
		// Run query
		Uri uri = ContactsContract.Contacts.CONTENT_URI;
		String[] projection = new String[] { ContactsContract.Contacts._ID,
				ContactsContract.Contacts.DISPLAY_NAME };
		String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '"
				+ ("1") + "'";
		String[] selectionArgs = null;
		String sortOrder = ContactsContract.Contacts.DISPLAY_NAME
				+ " COLLATE LOCALIZED ASC";

		return managedQuery(uri, projection, selection, selectionArgs,
				sortOrder);
	}

}

Make sure you give your application the permission to read the contacts. (Uses Permissions “android.permission.READ_CONTACTS” in AndroidManifest.xml)

9. Summary

Here in this complete tutorial we have seen:
1) ListView with Standard Layout
2)ListView with own Layout
3)Performance Optimization
4)List with SimpleCursorAdapter

10. Download sourcecode for all the tutorials

click here to download.

AUTHOR: Vikas Hiran
No Comments

Leave a Comment

Your email address will not be published.