How to Create Simple Lists using ListViews

Hello World! In this post, we’re going to learn how to use one of the most useful views in Android: the ListView. We can use ListViews to present data in the form of a list. We can choose any kind of data as input and display it however we want. That’s the power of a ListView. In this post, we’ll be creating a simple app that presents a list showing all of the countries of the world.

Note: While Android now has a much more generic RecyclerView, since our task is going to be fairly simple, we’ll stick to the ListView so we don’t have to deal with the additional complexities of the RecyclerView. To summarize, a RecyclerView is more generic version of a GridView and ListView. It allows developers to have greater power and control over the presentation of data and makes things like animations easier to do. However, with this greater control, we have to implement many things ourselves, such as a custom adapter, item layout, and view holder. For our purposes, a plain old ListView will suffice. With great power comes great responsibility!

All of source code for this project is in a ZIP file here.

Creating the Project

Let’s start up Android Studio and create a new project titled ListViewDemo. We can give any package name we want and select Android 6.0 Marshmallow as our minimum SDK version. We’ll just need an empty activity and we’ll leave the default names as is. We won’t need too much code to get our ListView working. First, we’ll need open up the Activity’s layout file in res/layout. We can replace the entire contents of the file with just the following code snippet:

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:id="@+id/listView" />

The above code will create a ListView for us and give it some properties. By setting the height and width of a top-level UI element to be match_parent , we are telling Android to make this UI element take up the entire screen, which is exactly what we want our ListView to do. We have some padding to the top and bottom so that the text in the list items aren’t right up against the top of the screen, making it difficult to read. Finally, we have the id  property so that we can refer to this ListView when we get to our source code.

For our model, we’ll be displaying all of the countries in the world, but we need a place to store that information. We’ll keep it in our strings.xml file in res/values. Open up that file and paste the following between the resources tag:

    <string-array name="countries_array">
        <item>Afghanistan</item>
        <item>Albania</item>
        <item>Algeria</item>
        <item>American Samoa</item>
        <item>Andorra</item>
        <item>Angola</item>
        <item>Anguilla</item>
        <item>Antarctica</item>
        <item>Antigua and Barbuda</item>
        <item>Argentina</item>
        <item>Armenia</item>
        <item>Aruba</item>
        <item>Australia</item>
        <item>Austria</item>
        <item>Azerbaijan</item>
        <item>Bahrain</item>
        <item>Bangladesh</item>
        <item>Barbados</item>
        <item>Belarus</item>
        <item>Belgium</item>
        <item>Belize</item>
        <item>Benin</item>
        <item>Bermuda</item>
        <item>Bhutan</item>
        <item>Bolivia</item>
        <item>Bosnia and Herzegovina</item>
        <item>Botswana</item>
        <item>Bouvet Island</item>
        <item>Brazil</item>
        <item>British Indian Ocean Territory</item>
        <item>British Virgin Islands</item>
        <item>Brunei</item>
        <item>Bulgaria</item>
        <item>Burkina Faso</item>
        <item>Burundi</item>
        <item>Cambodia</item>
        <item>Cameroon</item>
        <item>Canada</item>
        <item>Cape Verde</item>
        <item>Cayman Islands</item>
        <item>Central African Republic</item>
        <item>Chad</item>
        <item>Chile</item>
        <item>China</item>
        <item>Christmas Island</item>
        <item>Cocos (Keeling) Islands</item>
        <item>Colombia</item>
        <item>Comoros</item>
        <item>Congo</item>
        <item>Cook Islands</item>
        <item>Costa Rica</item>
        <item>Cote d\'Ivoire</item>
        <item>Croatia</item>
        <item>Cuba</item>
        <item>Cyprus</item>
        <item>Czech Republic</item>
        <item>Democratic Republic of the Congo</item>
        <item>Denmark</item>
        <item>Djibouti</item>
        <item>Dominica</item>
        <item>Dominican Republic</item>
        <item>East Timor</item>
        <item>Ecuador</item>
        <item>Egypt</item>
        <item>El Salvador</item>
        <item>Equatorial Guinea</item>
        <item>Eritrea</item>
        <item>Estonia</item>
        <item>Ethiopia</item>
        <item>Faeroe Islands</item>
        <item>Falkland Islands</item>
        <item>Fiji</item>
        <item>Finland</item>
        <item>Former Yugoslav Republic of Macedonia</item>
        <item>France</item>
        <item>French Guiana</item>
        <item>French Polynesia</item>
        <item>French Southern Territories</item>
        <item>Gabon</item>
        <item>Georgia</item>
        <item>Germany</item>
        <item>Ghana</item>
        <item>Gibraltar</item>
        <item>Greece</item>
        <item>Greenland</item>
        <item>Grenada</item>
        <item>Guadeloupe</item>
        <item>Guam</item>
        <item>Guatemala</item>
        <item>Guinea</item>
        <item>Guinea-Bissau</item>
        <item>Guyana</item>
        <item>Haiti</item>
        <item>Heard Island and McDonald Islands</item>
        <item>Honduras</item>
        <item>Hong Kong</item>
        <item>Hungary</item>
        <item>Iceland</item>
        <item>India</item>
        <item>Indonesia</item>
        <item>Iran</item>
        <item>Iraq</item>
        <item>Ireland</item>
        <item>Israel</item>
        <item>Italy</item>
        <item>Jamaica</item>
        <item>Japan</item>
        <item>Jordan</item>
        <item>Kazakhstan</item>
        <item>Kenya</item>
        <item>Kiribati</item>
        <item>Kuwait</item>
        <item>Kyrgyzstan</item>
        <item>Laos</item>
        <item>Latvia</item>
        <item>Lebanon</item>
        <item>Lesotho</item>
        <item>Liberia</item>
        <item>Libya</item>
        <item>Liechtenstein</item>
        <item>Lithuania</item>
        <item>Luxembourg</item>
        <item>Macau</item>
        <item>Madagascar</item>
        <item>Malawi</item>
        <item>Malaysia</item>
        <item>Maldives</item>
        <item>Mali</item>
        <item>Malta</item>
        <item>Marshall Islands</item>
        <item>Martinique</item>
        <item>Mauritania</item>
        <item>Mauritius</item>
        <item>Mayotte</item>
        <item>Mexico</item>
        <item>Micronesia</item>
        <item>Moldova</item>
        <item>Monaco</item>
        <item>Mongolia</item>
        <item>Montenegro</item>
        <item>Montserrat</item>
        <item>Morocco</item>
        <item>Mozambique</item>
        <item>Myanmar</item>
        <item>Namibia</item>
        <item>Nauru</item>
        <item>Nepal</item>
        <item>Netherlands</item>
        <item>Netherlands Antilles</item>
        <item>New Caledonia</item>
        <item>New Zealand</item>
        <item>Nicaragua</item>
        <item>Niger</item>
        <item>Nigeria</item>
        <item>Niue</item>
        <item>Norfolk Island</item>
        <item>North Korea</item>
        <item>Northern Marianas</item>
        <item>Norway</item>
        <item>Oman</item>
        <item>Pakistan</item>
        <item>Palau</item>
        <item>Panama</item>
        <item>Papua New Guinea</item>
        <item>Paraguay</item>
        <item>Peru</item>
        <item>Philippines</item>
        <item>Pitcairn Islands</item>
        <item>Poland</item>
        <item>Portugal</item>
        <item>Puerto Rico</item>
        <item>Qatar</item>
        <item>Reunion</item>
        <item>Romania</item>
        <item>Russia</item>
        <item>Rwanda</item>
        <item>Sqo Tome and Principe</item>
        <item>Saint Helena</item>
        <item>Saint Kitts and Nevis</item>
        <item>Saint Lucia</item>
        <item>Saint Pierre and Miquelon</item>
        <item>Saint Vincent and the Grenadines</item>
        <item>Samoa</item>
        <item>San Marino</item>
        <item>Saudi Arabia</item>
        <item>Senegal</item>
        <item>Serbia</item>
        <item>Seychelles</item>
        <item>Sierra Leone</item>
        <item>Singapore</item>
        <item>Slovakia</item>
        <item>Slovenia</item>
        <item>Solomon Islands</item>
        <item>Somalia</item>
        <item>South Africa</item>
        <item>South Georgia and the South Sandwich Islands</item>
        <item>South Korea</item>
        <item>South Sudan</item>
        <item>Spain</item>
        <item>Sri Lanka</item>
        <item>Sudan</item>
        <item>Suriname</item>
        <item>Svalbard and Jan Mayen</item>
        <item>Swaziland</item>
        <item>Sweden</item>
        <item>Switzerland</item>
        <item>Syria</item>
        <item>Taiwan</item>
        <item>Tajikistan</item>
        <item>Tanzania</item>
        <item>Thailand</item>
        <item>The Bahamas</item>
        <item>The Gambia</item>
        <item>Togo</item>
        <item>Tokelau</item>
        <item>Tonga</item>
        <item>Trinidad and Tobago</item>
        <item>Tunisia</item>
        <item>Turkey</item>
        <item>Turkmenistan</item>
        <item>Turks and Caicos Islands</item>
        <item>Tuvalu</item>
        <item>Virgin Islands</item>
        <item>Uganda</item>
        <item>Ukraine</item>
        <item>United Arab Emirates</item>
        <item>United Kingdom</item>
        <item>United States</item>
        <item>United States Minor Outlying Islands</item>
        <item>Uruguay</item>
        <item>Uzbekistan</item>
        <item>Vanuatu</item>
        <item>Vatican City</item>
        <item>Venezuela</item>
        <item>Vietnam</item>
        <item>Wallis and Futuna</item>
        <item>Western Sahara</item>
        <item>Yemen</item>
        <item>Yugoslavia</item>
        <item>Zambia</item>
        <item>Zimbabwe</item>
    </string-array>

 

The above XML just creates a string array that holds all of the countries of the world. One of the benefits of putting this in the res folder is that we can localize the strings to any particular language. This is just one of the many benefits of the Android resource system. To summarize the Android resource system, we can provide string files in different languages, layouts in different orientations, and other specifications and Android will choose the one that pertains to the user’s current situation at runtime. We just have to be thorough in providing Android with all of these resources. We can do this by appending a very specific sequence of characters after the “main” name of the folder (i.e. values, layout, drawable). For example, suppose we want to have a different dimensions file for tablet screens or screens with a width of 820 density-independent pixels (dp). We can create another folder called values and append “-w820dp” to the folder name. Then we can add any files to this folder and Android will only use these values if the device which runs our app has a width of 820dp.

Now that we have our data, we can actually link up our model and our view. Open up the MainActivity.java file and we’ll create a few member variables to hold data. We’ll create one for the ListView and another for the ArrayAdapter:

private ListView listView;
private ArrayAdapter<CharSequence> adapter;

The reason that the ArrayAdapter is a generic of CharSequence instead of String is because we’ll be grabbing string array from the strings.xml file. We can have a String array since CharSequence is an interface and String implements CharSequence, hence we can use String. Now that we have our member variables set up, we actually need to configure our adapter and ListView. Doing this setup in onCreate(Bundle) is ideal because that method is going to be called before the screen is actually visible to the user, so data will be ready as soon as the view is presented. In our onCreate(Bundle)  method, let’s add the following code:

listView = (ListView) findViewById(R.id.listView);
adapter = ArrayAdapter.createFromResource(this, R.array.countries_array, android.R.layout.simple_list_item_1);
listView.setAdapter(adapter);

The first line grabs a reference to the ListView. Then, we need to create a new adapter using a static utility method on ArrayAdapter called ArrayAdapter.createFromResource(Context, int, int) . The purpose of the method is to take the contents of the given string array and put it in the layout. The first parameter is the Context. In Android, the Context is the current state of the application. We use it to initialize views or to get something from our app resources or the system’s resources. Since Activity is a subclass of Context, we can pass in this as a valid object. The second parameter is the string array of countries. Since this is in our resources system and an array, we need to use the R class to access it via R.array.countries_array . The final parameter is the layout that we want to populate with the string array. In our case, we’re just using Android’s simplest ListView layout that consists of just a single TextView. Finally, we set the ListView’s adapter to be the one we just created. Now we should be able to run our application and see the results!

ListViews – 1

Setting up a ListView to display data is great, but we want some user interaction in our ListView. For example, when a user taps on a list item, we want to do something about it. To do this, we need to set up an event listener to notify us when the user taps on a list item. Event listeners work by allowing us to register and run a callback method when the event occurs. That callback method is in the form of an interface we pass in to the listener. There are several ways we can choose to implement an event listener: create a separate class that implements that interface and pass in a new instance of that class; use Java’s anonymous inner classes; or pass in this  and force our Activity to implement the interface and the callback method. For our case, it’ll look cleaner if we do the latter. Note that there are many different listeners so we have to choose the appropriate one for the event we want to receive information about. We can set the listener in the onCreate(Bundle)  method by executing listView.setOnItemClickListener(this); to set up our listener. This will make Android Studio throw an error and so we have to implement the interface in our Activity. Our class declaration changes to public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener. We also have to implement the callback method for in our class on the class level like the following.

@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
    Toast.makeText(this, adapter.getItem(position), Toast.LENGTH_SHORT).show();
}

You’ll notice we use Toasts in the above code. A Toast just shows a transparent overlay. We need to pass in a Context, which is just this  again. The second parameter is the text we want to show. We’re essentially grabbing the text at that position in the ListView. This means that when the user taps on a ListView item, we’ll just have a Toast that displays what’s on the ListView. The final parameter is just a constant corresponding to how long we want to show the Toast. However, the makeText(Context, CharSequence, int)  method just creates a Toast, we have to show it by calling show() on the newly created Toast message. This is all it takes to configure our ListView! We can see the final result below.

ListView – 2

Conclusion

In this post, we covered the basics of ListView and how to populate it with items from an adapter. For our purposes, we just used a string array in our strings.xml file. As a side note, we learned more about the Android resource system as well. In addition to populating a ListView, we also learned how to configure event listeners to be notified when some event happens regarding the ListView. We used that to display a Toast message to the user.