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 extendRecyclerView.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 anOrderViewHolder
from it.onBindViewHolder
should update the view holder with the item at the providedposition
.- The adapter should extend
RecyclerView.Adapter
, using yourViewHolder
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
withfindViewById
. - Set the
RecyclerView
’s adapter to be theOrderAdapter
you just created. - Create a
LayoutManager
and set it as theRecyclerView
’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.