Working with ListView – Part 1

featured

Lists are one of the most common UI elements used in Android applications. Be it a twitter client, SMS app, or even a preference screen, you will encounter lists fairly often. This series of articles will go through the most common uses of the ListView, from a simple list to a skinned list interface with custom UI elements.

Let’s start with the simplest of lists: a static list. Our static list will be a scrollable ListView with hard-coded text elements. To create this, we will add the ListView element to our layout (you can start with the HelloWorld app if you like, or create a new Activity)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	>
	
	<!-- Main content here -->
	<ListView
		android:id="@+id/news_list_view"
		android:entries="@array/test"
		android:layout_height="fill_parent"
		android:layout_width="fill_parent">
	</ListView>

</LinearLayout>

The above ListView refers to an array called “test” for it’s entries data. Create the file res/values/arrays.xml with the following content:

<?xml version="1.0" encoding="utf-8"?>
<resources>

	<string-array name="test">
		<item>1</item>
		<item>2</item>
		<item>3</item>
		<item>4</item>
		<item>5</item>
		<item>6</item>
		<item>7</item>
		<item>8</item>
		<item>9</item>
		<item>10</item>
	</string-array>

</resources>

We now have the data that will be populated in to the ListView. You can launch the app and you should see a list with the numbers 1 to 10. To make this more useful, we need to be able to respond to a click (press) or long press. We do this in code – add the following to your Activity:

public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);
	
	ListView mainListView = (ListView) findViewById(R.id.news_list_view);
	mainListView.setOnItemClickListener(new OnItemClickListener() {
		@Override
		public void onItemClick(AdapterView arg0, View arg1,
			int arg2, long arg3) {
			Toast.makeText(getApplicationContext(),
				"You clicked on item " + arg2,
				Toast.LENGTH_LONG).show();
		}
	});
}

The method ListView.setOnItemClickListener() is called with a new implementation of the OnItemClickListener class (using Java anonymous inner class syntax, which is used a lot in Android). In this implementation, we override the onItemClick() method and make it display a Toast message when an item is clicked (or pressed). Similarily ListView.setOnItemLongClickListener() method can be used to listen for a long press.

Static lists are rarely useful in a real app – typically, you will need to load dynamic data into the ListView. To do that, we can use the SimpleAdapter class provided by Android. This class allows us to supply it with data in an ArrayList object, and a layout for each row of the list. It will then populate the ListView with the data using the specified layout to render each row.

Let’s now define the layout for each row of the ListView. Let’s pretend that we are displaying some tweets from Twitter in a list, so we would like to display the tweeter’s name, time of the tweet, and the actual text of the tweet. Create res/layout/tweet.xml with the following content:

<?xml version="1.0" encoding="utf-8"?>
<!-- A row of tweet data for display -->
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:paddingBottom="20sp"
	android:orientation="vertical">
	
	<LinearLayout
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:orientation="horizontal">
		
		<TextView android:id="@+id/TWEET_SCREEN_NAME"
			android:text="AndroidZA"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:textStyle="bold"
			android:textSize="15sp"/>
		
		<TextView android:id="@+id/TWEET_CREATED_AT"
			android:text="10:30, 13th July 2010"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:layout_gravity="right"
			android:textStyle="bold"
			android:textSize="15sp"
			android:paddingRight="5dip"
			android:gravity="right"
			android:layout_weight="1"/>
	
	</LinearLayout>
	
	<LinearLayout
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:orientation="horizontal">
	
		<TextView android:id="@+id/TWEET_TEXT"
			android:text="Hi, this is a tweet. It should be 140 characters or less"
			android:paddingRight="5dip"
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:layout_weight="1"/>
	
	</LinearLayout>
</LinearLayout>

You can preview this layout by clicking the Layout tab at the bottom of the editor to see what each row will look like. I’ve added some sample data to the layout aid this. Notice the use of LinearLayout elements to align the TextView elements horizontally or vertically. I’ve also given each TextView element an id, which we will use later to populate each of them.

Now that we have the layout for the row, we can generate some sample data and load it into the ListView using the SimpleAdapter class. Add the following code to your Activity (I’ve omitted error-checking code for brevity):

public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);
	
	// populate some test data into our list
	ArrayList<HashMap> tweets = new ArrayList<HashMap>();
	for (int i = 0; i < 10; i++) {
		HashMap tweet = new HashMap();
		tweet.put("screen_name", "AndroidZA");
		tweet.put("created_at", String.valueOf(i) + " mins ago");
		tweet.put("text", "Test tweet " + i);
		tweets.add(tweet);
	}
	
	SimpleAdapter sa = new SimpleAdapter(
		getApplicationContext(),
		tweets,
		R.layout.tweet,
		new String[] { "screen_name", "created_at",	"text" },
		new int[] { R.id.TWEET_SCREEN_NAME, R.id.TWEET_CREATED_AT, R.id.TWEET_TEXT }) {
	};
	
	ListView mainListView = (ListView) findViewById(R.id.news_list_view);
	mainListView.setAdapter(sa);
}

In the above code, I created an ArrayList which contains a HashMap. I added data to the HashMap for each of our text elements: screen_name, created_at, and text. I then created a new SimpleAdapter implementation (anonymous inner classes again) and passed it the data, and the layout to use for each row. I also passed it two arrays which map the key in the HashMap, to the ID of the TextView element that corresponds to
that data. Finally, I passed the adapter object to the ListView, which then executes it. Run the app to see it in action. You can now add the same ListView.setOnItemClickListener() code from the previous example to make it respond to presses.

There we have it! A dynamically populated ListView that can respond to a press. You can now use the java.net package (for example) to make a request to Twitter, fetch a timeline, and then populate it into a list as above, thus creating a very simple Twitter client! In part 2, we well look at how to customize the look-and-feel of the list, to make it pretty!

Toby Kurien This article was written by Toby Kurien, an Electronics Engineer with over 15 years of programming experience. Specializing in Java, Web technologies, and Android development, he lives his passion through creating applications and writing articles. Follow him on Twitter: @tobykurien

© Copyright Android ZA 2010