Android RecyclerView Tutorial in Kotlin

Creating a RecyclerView in Kotlin isn't that hard. With some guidance, and a little effort, you too can create a RecyclerView. In this tutorial, we'll use ConstraintLayout, Kotlin and Android Studio to build it. First, open Android Studio and create a new project. Then select the following.

Then select Kotlin and androidx, then hit finish. We're well on our way to creating a RecylerView!

After you hit Finish, we're presented with Android Studio.

Android Studio.
MainActivity.kt, our Kotlin code.

Our Kotlin code resides in MainActivity.kt while our UI code lives in content_main.xml. This way, there is a clear separation between design and logic. We'll discuss at length later in this tutorial.

package com.example.myfirstrecyclerview

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)
    }
}
Our UI code lives in content_main.xml.

Open content_main.xml to see our UI code. Let's start by copying and pasting the code below into the file.

<?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="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".MainActivity"
    tools:showIn="@layout/activity_main">

</androidx.constraintlayout.widget.ConstraintLayout>

In the preview, it should look like the following.

Preview.

Next, let's add the RecyclerView element inside the ConstraintLayout tag.

<?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="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".MainActivity"
    tools:showIn="@layout/activity_main">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/myFirstRecyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Our preview now shows our "preview" list.

Switch files to MainActivity and add the following at the bottom of the onCreate() method.

        myFirstRecyclerView.apply {
            
        }

Then add a layoutManager and adapter. The adapter will initially show red, indicating there is an error. We'll fix this later.

       myFirstRecyclerView.apply {
            layoutManager = LinearLayoutManager(this@MainActivity)
            adapter = MyFirstAdapter()
        }

The complete MainActivity code is below.

package com.example.myfirstrecyclerview

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.content_main.*

class MainActivity : AppCompatActivity() {

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

        myFirstRecyclerView.apply {
            layoutManager = LinearLayoutManager(this@MainActivity)
            adapter = MyFirstAdapter()
        }
    }
}

To create a new Kotlin file in Android Studio, right click the package directly above MainActivity then select New -> Kotlin File/Class.

Create new.

MyFirstAdapter is initially bare, not much there:

package com.example.myfirstrecyclerview

class MyFirstAdapter {
}

Let's add to this class. First, let's make MyFirstAdapter extend RecyclerView.Adapter with a type of MyFirstAdapter.ViewHolder. We'll cover this in a second. Your code, while displaying errors, should look like this:

package com.example.myfirstrecyclerview

import androidx.recyclerview.widget.RecyclerView

class MyFirstAdapter : RecyclerView.Adapter<MyFirstAdapter.ViewHolder>() {
}

Then click on ViewHolder and press Alt+Enter, select Create Class 'View Holder', then save to the same file (select "MyFirstAdapter"). The new ViewHolder will appear as a class inside MyFirstAdapter:

package com.example.myfirstrecyclerview

import androidx.recyclerview.widget.RecyclerView

class MyFirstAdapter : RecyclerView.Adapter<MyFirstAdapter.ViewHolder>() {
    
    class ViewHolder {

    }
}

Make it extend RecyclerView.ViewHolder(view):

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

    }

Now click on "class MyFirstAdapter" and press Alt+Enter on your keyboard to select "implement methods." Next, select all three methods that appear and press OK. You may see the following.

package com.example.myfirstrecyclerview

import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

class MyFirstAdapter : RecyclerView.Adapter<MyFirstAdapter.ViewHolder>() {
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun getItemCount(): Int {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

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

    }
}

The TODO lines can be deleted. Let's now focus on getItemCount() since it's the easiest method to complete. Set it's size to 30 (or the number of rows you want in your list).

    override fun getItemCount() = 30

The other method we need to modify is onCreateViewHolder(). Make it read like this:

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

The complete MyFirstAdapter class is now complete! We're not finished yet; we need to create friend_row.xml for each RecyclerView row.

package com.example.myfirstrecyclerview

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView

class MyFirstAdapter : RecyclerView.Adapter<MyFirstAdapter.ViewHolder>() {

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

    override fun getItemCount() = 30

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    }

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

    }
}
Right click layout and select New -> Layout resource file.
Fill out friend_row, ConstraintLayout and click OK.

Open friend_row.xml, switch to Text mode (at the bottom of Android Studio).

Android Studio.
<?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"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Friend name here"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Now hit run:

Run, as show in Android Studio (next to the device name near the top of the screen).

If you don't already have an emulator or physical device (i.e. phone) plugged into your computer, follow the prompts to create a Virtual Device that you can run on your computer. After that, you should see the following in the Android Emulator:

Android emulator.

Nice work!

Lovin' my job at H-E-B Digital

Last month I got my 1-year badge from Jon, my Engineering Manager at H-E-B Digital! It's been a crazy 13 months, moving from office to office, for the better. When I first joined the team we were on the 1st and 5th floors of Capital Factory in Downtown Austin, Tex, which meant that we were constantly in the elevator, rushing from meeting to meeting.

Lunch at a recent store visit.

Now, we're at Eastside Tech Hub in East Austin, among a growing population.

Store visit.
Breakfast at a recent store visit.
Game night.
Mochi, the best dog ever.
The view from WeWork.
Snacks at WeWork.
Our meat processing plant. (Photo from H-E-Beginnings.)
Our values.
Beer and learn

Saturday, September 14th

I wake up particularly early this morning, at 6am. Not one to rest or take many breaks, and because I really wanted to, I started reading more of She Said, by the two New York Times investigative reporters who broke the story on Harvey Weinstein. What a book. After reading for 30 minutes, I fall asleep until 7am.

I go downtown to get a smoothie, where I get Amazon Prime and order a Raspberry Pi 4, the latest small computer. I spend $100, and it's totally worth it.

Then I head to the Downtown Austin Central Library where I search for interesting Pi projects. I found the perfect one, which I'll blog about later.