Android Tutorial: ListView

Farjanul Nayem
7 min readNov 26, 2021

--

A is a view for showing a scrollable list of items, which may come from a list adapter or an array adapter. Selecting an item in a ListView triggers an event for which you can write a listener.

If an activity contains only one view that is a, you can extend ListActivity instead of

as your activity class. Using ListActivity is convenient as it comes with a number of useful features.

This chapter shows how you can use the ListView and ListActivity as well as create a custom ListAdapter and style a ListView in three sample applications.

Android ListView

Technically, android.widget.ListView , the template for creating a ListView, is a descendant of the View class. You can use it the same way you would other views. What makes ListView a bit tricky to use is the fact that you have to obtain a data source for it in the form of a ListAdapter. The ListAdapter also supply the layout for each item on the ListView, so the ListAdapter really plays a very important role in the life of a ListView.

The android.widget. ListAdapter interface is a subinterface of android.widget. Adapter . The close relatives of this interface are shown in Figure 1.1.

Creating a ListAdapter is explained in the next section, “Creating a ListAdapter.” Once you have a ListAdapter, you can pass it to a ListView’s setAdapter method:

listView.setAdapter(listAdapter);

You can also write a listener that implements AdapterView.OnItemClickListener and pass it to the ListView’s setOnItemClickListener method. The listener will be notified every time a list item is selected and you can write code to handle it, like so.

listView.setOnItemClickListener(new
AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, final View view,
int position, long id) {
// handle item
});

Creating A ListAdapter

As mentioned in the previous section, the trickiest part of using a is creating a data source for it. You need a ListAdapter and as you can see in Figure 1.1 you have at least two implementations of ListAdapter that you can use.

One of the concrete implementations of ListAdapter is the ArrayAdapter class. An ArrayAdapter is backed by an array of objects. The string returned by the toString method of each object is used to populate each item in the ListView.

The ArrayAdapter class offers several constructors. All of them require that you pass a and a resource identifier that points to a layout that contains a . This is because each item in a ListView is a TextView. These are some of the constructors in the ArrayAdapter class.

public ArrayAdapter(android.content.Context context, int resourceId) 
public ArrayAdapter(android.content.Context context, int resourceId,
T[] objects)

If you do not pass an object array to a constructor, you will have to pass one later. As for the resource identifier, Android provides some pre-defined layouts for a ListAdapter . The identifiers to these layouts can be found in the android.R.layout class. For example, you can create an ArrayAdapter using this code snippet in your activity.

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, objects);

Using android.R.layout.simple_list_item_1 will create a ListView with the simplest layout where the text for each item is printed in black. Alternatively, you can use android.R.layout.simple_expandable_list_item_1 . However, you probably want to create your own layout and pass it to the constructor, instead. This way you would have more control over the look and feel of your ListView.

Most of the time you can use a string array as the data source for your ListView. You can create a string array programmatically or declaratively. Doing it programmatically is simple and you do not have to deal with an external resource:

String[] objects = { "item1", "item2","item-n" };

The disadvantage of this approach is that updating the array would require you to recompile your class. Creating a string array declaratively, on the other hand, gives you more flexibility as you can easily edit the elements.

To create a string array declaratively, start by creating a string-array element in your strings.xml file under . For example, the following is a string-array named players.

<string-array name="players"> 
<item>Player 1</item>
<item>Player 2</item>
<item>Player 3</item>
<item>Player 4</item>
</string-array>

When you save the strings.xml file, Android Studio will update your generated class and add a static final class named array, if none exists, as well as add a resource identifier for the string-array element to the array class. As a result, you now have this resource identifier to access your string array from your code:

R.array.players

To convert the user-defined string array to a Java string array, use this code.

String[] values = getResources().getStringArray(R.array.players);

You can then use this string array to create an ArrayAdapter .

Using A ListView

The ListViewDemo1 application shows how to use a that is backed by an ArrayAdapter . The array that supplies values to the ArrayAdapter is a string array defined in the strings.xml file. Listing 1.1 shows the strings.xml file.

Listing 1.1: The res/values/strings.xml file for ListViewDemo1

<?xml version="1.0" encoding="utf-8"?> 
<resources>
<string name="app_name">ListViewDemo1</string>
<string name="action_settings">Settings</string>

<string-array name="players">
<item>Player 1</item>
<item>Player 2</item>
<item>Player 3</item>
<item>Player 4</item>
<item>Player 5</item>
</string-array>
</resources>

The layout for the ArrayAdapter is defined in the list_item.xml file presented in Listing 1.2. It is located under and contains a element. This layout will be used as the layout for each item in the ListView.

Listing 1.2: The list_item.xml file

<?xml version="1.0" encoding="utf-8"?> 
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/list_item"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="7dip"
android:textSize="16sp"
android:textColor="@android:color/holo_green_dark"
android:textStyle="bold" >
</TextView>

The application consists of only one activity, MainActivity . The layout file ( activity_main.xml ) for the activity is given in Listing 1.3 and the MainActivity class in Listing 1.4.

Listing 1.3: The activity_main.xml file for ListViewDemo1

<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/listView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

Listing 1.4: The MainActivity class for ListViewDemo1

package com.example.listviewdemo1; 
import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] values = getResources().getStringArray(
R.array.players);

ArrayAdapter<String> adapter = new ArrayAdapter<String>(
this, R.layout.list_item, values);

ListView listView = (ListView) findViewById(R.id.listView1);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new
AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent,
final View view, int position, long id) {
String item = (String)
parent.getItemAtPosition(position);
AlertDialog.Builder builder = new
AlertDialog.Builder(MainActivity.this);
builder.setMessage("Selected item: "
+ item).setTitle("ListView");
builder.create().show();
Log.d("ListView", "Selected item : " + item);
}
});
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
}

Figure 1.2 shows the application.

Extending ListActivity and Writing A Custom Adapter

If your activity will only have one component that is a ListView, you should consider extending the ListActivity class instead of Activity. With ListActivity , you do not need a layout file for your activity. ListActivity already contains a ListView and you do not need to attach a listener to it. On top of that, the ListActivity class already defines a setListAdapter method, so you just need to call it in your method. In addition, instead of creating an AdapterView.OnItemClickListener, you just need to override the ListActivity’s onListItemClickmethod, which will be called when an item on the gets selected.

The ListViewDemo2 application shows how to use ListActivity. The application also demonstrates how to create a custom ListAdapter by extending the ArrayAdapter class and creating a layout file for the custom ListAdapter.

The layout file for the custom ListAdapter in ListViewDemo2 is presented in Listing 1.5. It is named pretty_adapter.xml file and is located under .

Listing 1.5: The pretty_adapter.xml file

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
android:id="@+id/icon"
android:layout_width="36dp"
android:layout_height="fill_parent"/>
<TextView
android:id="@+id/label"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:padding="12dp"
android:textSize="18sp"
android:textColor="@android:color/holo_blue_bright"/>
</LinearLayout>

Listing 1.6 shows the custom adapter class, called PrettyAdapter.

Listing 1.6: The PrettyAdapter class

package com.example.listviewdemo2; 
import android.content.Context;
import android.graphics.drawable.Drawable;
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 PrettyAdapter extends ArrayAdapter<String> {
private LayoutInflater inflater;
private String[] items;
private Drawable icon;
private int viewResourceId;

public PrettyAdapter(Context context,
int viewResourceId, String[] items, Drawable icon) {
super(context, viewResourceId, items);
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.items = items;
this.icon = icon;
this.viewResourceId = viewResourceId;
}

@Override
public int getCount() {
return items.length;
}

@Override
public String getItem(int position) {
return items[position];
}

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

@Override
public View getView(int position, View convertView,
ViewGroup parent) {
convertView = inflater.inflate(viewResourceId, null);

ImageView imageView = (ImageView)
convertView.findViewById(R.id.icon);
imageView.setImageDrawable(icon);

TextView textView = (TextView)
convertView.findViewById(R.id.label);
textView.setText(items[position]);
return convertView;
}
}

The custom adapter must override several methods, notably the method, which must return a View that will be used for each item on the . In this example, the view contains an ImageView and a . The text for the TextView is taken from the array passed to the PrettyAdapter instance.

The last piece of the application is the MainActivity class in Listing 1.7. It extends ListActivity and is the only activity in the application.

Listing 1.7: The MainActivity class for ListViewDemo2

package com.example.listviewdemo2; 
import android.app.ListActivity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ListView;

public class MainActivity extends ListActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Since we're extending ListActivity, we do
// not need to call setContentView();

Context context = getApplicationContext();
Resources resources = context.getResources();

String[] items = resources.getStringArray(
R.array.players);
Drawable drawable = resources.getDrawable(
R.drawable.pretty);

setListAdapter(new PrettyAdapter(context,
R.layout.pretty_adapter, items, drawable));
}

@Override
public void onListItemClick(ListView listView,
View view, int position, long id) {
Log.d("listView2", "listView:" + listView +
", view:" + view.getClass() +
", position:" + position );
}
}

If you run the application, you will see an activity like that in Figure 1.3.

Styling the Selected Item

It is often desirable that the user be able to see clearly the currently selected item in a . To make the selected item look different than the rest of the items, set the ListView’s choice mode to CHOICE_MODE_SINGLE , like so.

listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

Then, when constructing the underlying ListAdapter , use a layout with an appropriate style. The easiest is to pass the simple_list_item_activated_1 field. For example, when used in a ListView, the following ArrayAdapter will cause the selected item to have a blue background.

See the full article here: https://www.djuices.com/android-tutorial-listview/

Originally published at https://www.djuices.com on November 26, 2021.

--

--