Getting to know ListView in Android

Christian Vasquez - Jan 12 '18 - - Dev Community

WARNING

This will be a loooong post, so take your time to read through it.

The following code samples are written in Kotlin and I will asume that you are a bit familiar with Android Studio and the project structure of a basic Android app.

If you are currently learning Android development, chances are that you will come across with ListView. Which is a special kind of View used for displaying a list of items (I can already hear you thinking: "duh!") that is quite common in Android.

Although, it is being replaced by RecycleView because of performance and animations limitations that the ListView faces.

But it's good for you to be at least familiar with how it works, as it might also help you understand why and how RecycleView works later on.

Requirements

Setup the layout

Head over to your activity_main.xml, which should initially look like this:



<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.chrisvasqm.gettingtoknowlistview.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>


Enter fullscreen mode Exit fullscreen mode

The default layout consists of a TextView on the center of the screen via constraints. Cool, but we won't need that, so go ahead and 🗑️ it.

We will replace everything with:



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


Enter fullscreen mode Exit fullscreen mode

Now if you check your Android Studio's Preview panel, it should look like this:

Preview panel

Great! We can see that the list is already showing some content.

So, let's go ahead and try it out. Run the app on your device/emulator.

Got a blank screen? Awesome! That's what is expected 👍.

Why?

Because the ListView shows those sample items so you can see how it would look when you fill it with data, but we haven't done that... yet.

Adding data to the ListView

There are various ways to achieve this, I'll show you all 3 of them (unless there's more and I'm not aware of them).

1) Using a string-array resource file

The simplest way to fill a ListView is by using a string-array resource file.

Head over to your app/res/values/ folder and create a new XML file, let's call it arrays.xml, then add the following code to it:



<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="list_items">
        <item>One</item>
        <item>Two</item>
        <item>Three</item>
        <item>Four</item>
        <item>Five</item>
    </string-array>
</resources>


Enter fullscreen mode Exit fullscreen mode

In order to add it our ListView, we can do it right inside the activity_main.xml layout by adding the the entries attribute to it:



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


Enter fullscreen mode Exit fullscreen mode

Now run the app again and you should be able to see this:

List of items

2) Using an ArrayList & ArrayAdapter

In order to do this, we'll need to add an id attribute to our ListView, I'll name it "listView":



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


Enter fullscreen mode Exit fullscreen mode

Then, head over to your MainActivity.java and make a List<> of Strings:



val items = listOf(
    "First",
    "Second",
    "Third",
    "Fourth",
    "Fifth"
)


Enter fullscreen mode Exit fullscreen mode

The listOf() function takes in any number of arguments and returns a List<TYPE> object of that same type.

Plus, it is immutable. And by that I mean that it does not have any add() or remove() methods, like a regular List would have. In order to get them, you must use the mutableListOf() method instead.

Now we need to pass in our items list to an ArrayAdapter object:



val arrayAdapter = ArrayAdapter<String>(
    this,
    android.R.layout.simple_list_item_1,
    items
)


Enter fullscreen mode Exit fullscreen mode

The android.R.layout.simple_list_item_1 is a layout made out of only a TextView that is part of the android package that has a R.layout folder, which holds commonly used resources so we don't have to make our own (but we will in our next section).

Now that we have our arrayAdapter ready, we can set our ListViews's adapter to it:



listView.adapter = arrayAdapter


Enter fullscreen mode Exit fullscreen mode

Our MainActivity's OnCreate method should look like this now:



override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val items = listOf(
        "First",
        "Second",
        "Third",
        "Fourth",
        "Fifth"
    )

    val arrayAdapter = ArrayAdapter<String>(
        this,
        android.R.layout.simple_list_item_1,
        items
    )

    listView.adapter = arrayAdapter
}


Enter fullscreen mode Exit fullscreen mode

What are you waiting for? go run the app and check it out yourself!

You should be able to see this now:

ListView working with ArrayAdapter

Well done, but... let's take it to the next level 😎!

3) Using a Custom ArrayAdapter

At the end of this section, we will be doing this:

ListView with CustomArrayAdapter

First thing we will need is to create a class that will hold our Contact related data:



class Contact(
    val imageResource: Int,
    val name: String,
    val description: String
)


Enter fullscreen mode Exit fullscreen mode

Now we can create our Custom ArrayAdapter by creating a class that will inherit from the ArrayAdapter class and since we are going to be displaying Contacts, I will name it ContactArrayAdapter:



class ContactArrayAdapter(context: Context, contacts: List<Contact>)
    : ArrayAdapter<Contact>(context, 0, contacts) {

    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        val rootView = convertView ?: LayoutInflater.from(context).inflate(R.layout.list_item, parent, false)
        val currentContact = getItem(position)

        rootView.contactImage.setImageResource(currentContact.imageResource)
        rootView.contactName.text = currentContact.name
        rootView.contactDescription.text = currentContact.description

        return rootView
    }
}


Enter fullscreen mode Exit fullscreen mode

You will probably notice that the R.layout.list_item will be highlighted with red, that's because we haven't created our custom layout that will show our contactImage, contactName and contactDescription.

Head over to your app/res/layout/ folder, Right Click on the layout folder and select New > Layout resource file. Name it "list_item" and hit OK.

Now add this XML to it:



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:padding="16dp">

    <ImageView
        android:id="@+id/contactImage"
        android:layout_width="64dp"
        android:layout_height="64dp"
        app:srcCompat="@mipmap/ic_launcher_round" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="vertical"
        android:paddingLeft="16dp">

        <TextView
            android:id="@+id/contactName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Contact Name"
            android:textColor="@android:color/black"
            android:textSize="18sp" />

        <TextView
            android:id="@+id/contactDescription"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Contact Description" />
    </LinearLayout>

</LinearLayout>


Enter fullscreen mode Exit fullscreen mode

Copy our profile images from my profile and Jorge's, and then paste them in your app/res/drawable/ folder.

And now we finally have everything in place to set things in motion.

Go back to your MainActivity and refactor it so we now have a List<Contact> and instead of using the ArrayAdapter<String> we will use our new ContactArrayAdapter.

Which should look like:



class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val contacts = listOf(
                Contact(R.drawable.contact_chris, "Christian Vasquez", "QA Analyst"),
                Contact(R.drawable.contact_david, "Jorge Peña", ".NET Web Developer")
        )

        val arrayAdapter = ContactArrayAdapter(this, contacts)

        listView.adapter = arrayAdapter
    }
}


Enter fullscreen mode Exit fullscreen mode

Run the app and you should be able to see our final result:

ListView with CustomArrayAdapter

What? Your images aren't circular?

Oh... I'll leave that as a homework for you :)

Cough cough hint cough cough.

Final words

YOU MADE IT 👏👏👏

Make sure you high five yourself because THAT was a lot of work!

And I hope you learned something new along the way 🤓.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .