In this tutorial series, we will learn about all the essential and fundamental tools and concepts that you should know as an android developer. Today’s topic is RecyclerView.

Almost every app that you use displays a scrollable list of items, be it connectivity apps like Instagram, WhatsApp and Twitter or utility apps like Todoist, Pocket and Notion.

The most efficient tool to display a scrollable list of items in Android Programming is the RecyclerView.

Fundamentals of UI in Android

Views are the fundamental building-blocks of user interface components in Android. You must have come across different Views such TextView, EditText and ContraintLayout which is a ViewGroup. ViewGroups are views which can contain other views. RecyclerView is one such ViewGroup which can contain a list of Views.

Why Use RecyclerView? - RecyclerView vs ListView

Let’s say that you have 100 items in your data-set that you want to display as a scrollable list, but only 5 items can be visible to the user on the screen at a time, owing to the constrains of the screen size. If we a use a ListView, 100 View Objects will be created to contain these 100 items. This is expensive as far as efficiency is concerned. RecyclerView makes the process much more efficient by creating only 5 view-objects (since that is the number of items visible on the screen at a time) and recycles the views with updated data to contain the rest of the items using things like ViewHolder, Adapter and LayoutManager (more about these in a second). Let’s jump right into Android Studio to see how it actually works by coding an app that display a list of your twitter contacts. The app that we will code in this tutorial will look like this:

Step 1: Plan your Layout

Create a new project -> empty activity in Android Studio. We will start by editing the Activity Layout activity_main.xml which by default contains a ConstraintLayout with a TextView. But we don’t need them because we want the entire layout to contain a RecyclerView. So remove the TextView and replace the ConstraintLayout with a RecyclerView:

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/ContactList"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">



</androidx.recyclerview.widget.RecyclerView>

Next we need to design how each element in the list is going to look like and behave. For that, we will define a new layout file item_view.xml in the res/layout folder:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:gravity="center_vertical"
    android:id="@+id/container">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/contactName"
            style="@style/TextAppearance.AppCompat.Headline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="textView" />

        <TextView
            android:id="@+id/contactNumber"
            style="@style/TextAppearance.AppCompat.Body1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="0000000000" />
    </LinearLayout>

    <View android:layout_weight="1" android:layout_width="wrap_content" android:layout_height="0dp"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:text="CALL" />

</LinearLayout>

This is how our design looks like:

Step 2: Edit Gradle Files

In Gradle Scripts/build.gradle add this under dependencies :

implementation 'androidx.recyclerview:recyclerview:1.2.1'

And under plugins, add id 'kotlin-android-extensions'

Click Sync Now, once that’s done we will be able to use kotlin-extensions and recyclerview in our project.

Step 3: Creating the Adapter Class

In android, an Adapter is the bridge between UI components and data source that helps us to fill data in UI components, also called data binding. In RecyclerView, the Adapter creates ViewHolder objects which are wrappers around Views that contain layouts for each individual item in the list. So let’s create a ViewHolder class in our Adapter class. Create a new Kotlin class called MyAdapter in your project sub-folder where MainActivity.kt exists, and add this code:

package com.avionmission.rvpractice3

import androidx.recyclerview.widget.RecyclerView

class MyAdapter {
    inner class MyViewHolder(itemView: View): RecyclerView.ViewHolder() {
        var contactName = itemView.findViewById<TextView>(R.id.contactName)
        var contactNumber = itemView.findViewById<TextView>(R.id.contactNumber)
    }
}

In MyViewHolder class, we added some references to the Views in our item_view.xml layout file, that we will use later.

Now, we will make MyAdapter() class inherit RecyclerView.Adapter and pass the MyViewHolder() class to it:

class MyAdapter(): RecyclerView.Adapter<MyAdapter.MyViewHolder>(){

This will throw an error in android studio, click on the red bulb that appears when you hover over class MyAdapter() and you will see the option to Implement Members, click on it and you will see the following options:

Select all, and click OK.

This automatically generate three functions:

class MyAdapter(): RecyclerView.Adapter<MyAdapter.MyViewHolder>(){
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        TODO("Not yet implemented")
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        TODO("Not yet implemented")
    }

    override fun getItemCount(): Int {
        TODO("Not yet implemented")
    }

    inner class MyViewHolder(itemView: View): RecyclerView.ViewHolder() {
        var contactName = itemView.findViewById<TextView>(R.id.contactName)
        var contactNumber = itemView.findViewById<TextView>(R.id.contactNumber)
    }
}

Step 4: Creating a Data Class

Data Class is a class that only contains data and does not perform any operation. The advantage of using the data keyword is that kotlin provides us many functionalities for data classes.

In the MainActivity.kt we will create a Data Class, we will name it Contact, so add this just above the class MainActivity and below the imports:

data class Contact(val title:String, val number:Int)

In MyAdapter.kt we will change the parameter of MyAdapter to take in the Data Class we created:

class MyAdapter(val contacts: List<Contact>): RecyclerView.Adapter<MyAdapter.MyViewHolder>(){

Step 5: Building the Adapter Class

Let’s start adding code to the three member functions of the adapter class one by one, starting with onCreateViewHolder(). As the name suggests, this function is called when a ViewHolder is created. Once a ViewHolder is created, it needs to hold a View, and we will derive that view from the item_view.xml that we created earlier in Step 1. To do that we will use LayoutInflater, which converts xml code into java/kotlin objects which can be rendered on screen.

Here’s how onCreateViewHolder() should look like:

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

But how will the data that will be filled in the Views reach the adapter? For that we will add a List called contacts in the parameters of our MyAdapter() class:

class MyAdapter(val contacts: List<Contact>): RecyclerView.Adapter<MyAdapter.MyViewHolder>(){

The next member function that we will edit is the getItemCount(), which simply returns the number of items in the list contacts.:

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

That leaves us with only one member-function to deal with, which is onBindViewHolder(), which binds the data i.e fill the data in the UI components:

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        holder.contactName.text = contacts[position].title
        holder.contactNumber.text = contacts[position].number.toString()
    }

Step 6: Implementing the Adapter in MainActivity

Now we need data to pass to the adapter, so create a list of contacts in MainActivity():

val myContacts= mutableListOf<Contact>()

Then add items to this list, enough items to make it scrollable, which will be in the form of the Contact data class we created earlier:

        myContacts.add(Contact("Elon Musk", 1234567890))
        myContacts.add(Contact("Jeff Bezos", 1234567890))
        myContacts.add(Contact("Bill Gates", 1234567890))
        myContacts.add(Contact("Warren Buffett", 1234567890))
        myContacts.add(Contact("Larry Page", 1234567890))
        myContacts.add(Contact("Sergey Brin", 1234567890))
        myContacts.add(Contact("Larry Ellison", 1234567890))
        myContacts.add(Contact("Steve Ballmer", 1234567890))
        myContacts.add(Contact("Ratan Tata", 1234567890))
        myContacts.add(Contact("Mukesh Ambani", 1234567890))
        myContacts.add(Contact("Gautam Adani", 1234567890))
        myContacts.add(Contact("Michael Bloomberg", 1234567890))
        myContacts.add(Contact("Mark Zuckerberg", 1234567890))
        myContacts.add(Contact("Zhong Shanshan", 1234567890))
        myContacts.add(Contact("Charles Koch", 1234567890))

Open activity_main.xml and you will notice we had set the id of our parent element RecyclerView to be contactList. We will reference our recycler view contactList and set it’s adapter and LayoutManager:

        ContactList.adapter = MyAdapter(myContacts)
        ContactList.layoutManager = LinearLayoutManager(this)

layoutManager is responsible for measuring and positioning item views within a RecyclerView, it lays out the items in a grid.

Run your app in the emulator and you should see this:

Conclusion

This process would have been easier if we simply used a ListView, but it is much more efficient to use RecyclerView when dealing with large amount of data. We learned how to code the layout files, Adapter and ViewHolder classes, and use Data Class to store data. You can ask any questions or doubts you may have in the comments.