25 January 2021
Using a Recycler View to display list items

What is a Recycler View?

The RecyclerView is a component and library of the Android SDK that makes it much simpler to display long lists. Before the RecyclerView came along, displaying a list with a large or unknown amount of items would be an involved process.

Imagine you wanted to display a list of 1000 items, each with an image and some text: Would you create 1000 views upfront? How would you know when to load each of the images?

The RecyclerView solved a lot of these issues and includes several other modernizations that make it worthwhile to use it with lists of any size.

The Item Layout

The first step to using a RecyclerView would typically be to design the layout that will be used for each item. The layout below contains two TextView views positioned one above the other.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="72dp">

    <TextView
        android:id="@+id/title_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="14dp"
        app:layout_constraintBottom_toTopOf="@id/subtitle_text_view"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Example Title Text" />

    <TextView
        android:id="@+id/subtitle_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="14dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/title_text_view"
        tools:text="Example subtitle text" />

</androidx.constraintlayout.widget.ConstraintLayout>

The Item

The list will need a list of items to display. You might already have a list of items however, I normally create a small DTO class that encapsulates the minimum amount of fields we need to display in the list.

data class OrderItem(
    val itemId: String,
    val displayName: String
)

The Adapter

The next step is to create your RecyclerView.Adapter. The adapter has one job: To bind a list of items to views that are displayed by a RecyclerView The adapter should not contain any business logic, it should be provided with a list of items and only be responsible for binding the objects to the views.

class OrderAdapter(

        private val orders: List<OrderItem>
        
) : RecyclerView.Adapter<OrderAdapter.OrderViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrderViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_order_layout, parent, false)
        return OrderViewHolder(view)
    }

    override fun onBindViewHolder(holder: OrderViewHolder, position: Int) {
        val item = orders[position]
        holder.titleTextView.text = item.displayName
        holder.subtitleTextView.text = item.itemId
    }

    override fun getItemCount(): Int {
        return orders.size
    }


    class OrderViewHolder(view: View) : RecyclerView.ViewHolder(view) {

        val titleTextView: TextView = view.findViewById(R.id.title_text_view)
        val subtitleTextView: TextView = view.findViewById(R.id.subtitle_text_view)

    }

}

This adapter is going to display a list of OrderItem objects. To keep the tutorial simple, the list will be immutable.

Adapter Components

  • The adapter has one construction parameter: The list of items to be displayed.
  • There is a nested class called OrderViewHolder. This represents the re-useable view of a single list item and should extend RecyclerView.ViewHolder.
  • getItemCount should return the number of items in our list.
  • onCreateViewHolder should inflate the XML layout of our list item we created earlier and create an OrderViewHolder from it.
  • onBindViewHolder should update the view holder with the item at the provided position.
  • The adapter should extend RecyclerView.Adapter, using your ViewHolder class as the type argument.

Usage

In your Activity or Fragment layout, the RecyclerView can be used as follows:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/order_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </androidx.recyclerview.widget.RecyclerView>

</androidx.constraintlayout.widget.ConstraintLayout>

In the Fragment or Activity code (typically in onCreate):

val items = listOf(
    OrderItem("123", "Order 123"),
    OrderItem("234", "Order 234")
)

val orderAdapter = OrderAdapter(items)

val recyclerView = findViewById<RecyclerView>(R.id.order_recycler_view)
recyclerView.adapter = orderAdapter
recyclerView.layoutManager = LinearLayoutManager(
    this, RecyclerView.VERTICAL, false
)
  • Create a list of items to be displayed by your adapter. These would typically be fetched from your data access layer or a RESTful API call.
  • Create an instance of your OrderAdapter, providing it with the list of items.
  • Obtain a reference to the RecyclerView with findViewById.
  • Set the RecyclerView’s adapter to be the OrderAdapter you just created.
  • Create a LayoutManager and set it as the RecyclerView’s layout manager property.

That’s it! Running the application should now display a list of OrderItem objects.

How it works

The adapter will create roughly as many OrderViewHolder objects as can fit on the device’s screen.

As the user scrolls, list items will move off the screen. Each time a new item is about to appear on the screen, the RecyclerView will call onBindViewHolder with the item that’s about to appear, and re-use an existing OrderViewHolder.

This way, if we had provided the adapter with a list of 1000 OrderItem objects, it only needs to create a few dozen (or fewer) views, saving a huge amount of resources.

If you’ve found this tutorial useful, you may want to try View Binding to remove some boilerplate findViewById calls.