DEV Community

Nick Shulhin
Nick Shulhin

Posted on

Scrolling... Scrolling... RecyclerView for Android with Kotlin!

Scrolling

We all love scrolling (some weird people swipe ¯_(ツ)_/¯).

Scrolling is a major interaction performed almost in every application around.

Let’s have a look what’s under the hood of Android implementation of “efficient scrolling” called RecyclerView!


Part One: What is Recycler View and what does it actually recycle? ♻️


RecyclerView initiates an efficient way of creating ViewHolder objects, binding them with data and reusing according to a list state.

Imagine, you received 44442 emails on your mobile application (Must be very popular!).

Theoretically, we would think that for every single email there should be a “cell view” created with email details such as title and short description. But we have… a lot of emails… What to do?

RecyclerView comes to help! But how?

It consists from three main elements: cell layout, Adapter and ViewHolder objects.

Cell layout represents an XML design blueprint of a list item. Something like this:

cell

As a next step, Adapter uses a data from the email server, and “binds” XML view to a particular data such as title or delivery time.

And to perform this binding, Adapter manages something which is called ViewHolder - a class which belongs to RecyclerView, responsible for displaying an item in a view.

And here comes amazing part:

Instead of creating 44442 views for each of our emails, RecyclerView reuses already created view holders which left an observable area of the screen.

What?

what

Imagine, your list of emails occupies full screen height and can contain 10 emails to be showed.

You start scrolling up.

⬆️

Once the top view is out of view, it is being reused by RecyclerView, with new data and pushed as a new bottom element. Something like that.

Enough of theory, let’s do practical part! 🔨


Part Two: Let’s create a RecyclerView with… Kotlin! ♻️


Kotlin is love, Kotlin is life (me ⓒ).

From my point of view, Kotlin is one of the best things which happened to Android :)

It is super easy to write, has a functional approach, easy to understand and hides a lot of boilerplate logic.

What are we waiting for? Let’s create our “email” app project!

NOTE: All ready copy-paste code is available here

A simple EmptyActivity will be fine for our use case:

setup

Next, let’s create our item/cell layout!

For a simple preview, we can use a title, description and a time.

Let’s create one in res/layout folder named email_item_layout.xml:

item

Closer look:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:background="#FFECECEC"
    android:orientation="horizontal"
    android:weightSum="1">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_weight="0.2"
        android:orientation="vertical"
        android:padding="10dp">

        <TextView
            android:id="@+id/email_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Let's go to Sydney Vivid tonight!"
            android:textColor="@color/colorPrimaryDark"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/email_description"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="Hey, Nick! There is amazing show near..." />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="0.8"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/email_time"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="10:38" />
    </LinearLayout>
</LinearLayout>

Alright, what’s next? Ah, unfortunately RecyclerView doesn’t come by default, so we need to import it as external dependency in our build gradle file:

implementation 'com.android.support:recyclerview-v7:28.0.0'

Once it is done, we can create our email data class! We can create “models” package and declare a simple Email class which would contain title, description and delivery time as String attributes:

data class Email(val title: String, val description: String, val time: String)

Done!

Now one of the most interesting parts: The Mighty Adapter!

Let’s create a file named EmailAdapter in new package called “adapters”.

Our EmailAdapter would accept a list of Email objects, context as well as contain a custom ViewHolder:

class EmailAdapter(private val emailList: List<Email>, private val context: Context) : RecyclerView.Adapter<EmailAdapter.EmailViewHolder>() {

    override fun onBindViewHolder(emailViewHolder: EmailViewHolder, index: Int) {
        emailViewHolder.titleTextView.text = emailList[index].title
        emailViewHolder.descriptionTextView.text = emailList[index].description
        emailViewHolder.timeTextView.text = emailList[index].time
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmailViewHolder {
        return EmailViewHolder(LayoutInflater.from(context).inflate(R.layout.email_item_layout, parent, false))
    }

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

    inner class EmailViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val titleTextView: TextView = view.findViewById(R.id.email_title)
        val descriptionTextView: TextView = view.findViewById(R.id.email_description)
        val timeTextView: TextView = view.findViewById(R.id.email_time)

    }
}

onCreateViewHolder is responsible for inflating XML layout of our email item into an EmailViewHolder object.
EmailViewHolder class extends ViewHolder and references views such as title, description and time TextViews we declared inside our XML layout, to be used for a data injection inside onBindViewHolder function.

We are almost done!!!

Now we need to place our RecyclerView XML declaration into activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/email_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</android.support.constraint.ConstraintLayout>

Next step will be to initiate RecyclerView inside MainActivity, and feed some random almost-real email data objects :)

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val fakeEmails = generateFakeEmails()
        setUpEmailRecyclerView(fakeEmails)
    }

    private fun setUpEmailRecyclerView(emails: List<Email>) {
        val layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
        val emailRecyclerView = findViewById<RecyclerView>(R.id.email_recycler_view)
        val recyclerAdapter = EmailAdapter(emails, this)
        emailRecyclerView.layoutManager = layoutManager
        emailRecyclerView.adapter = recyclerAdapter
    }

    private fun generateFakeEmails(): List<Email> {
        val titles = listOf(
                "Hot dogs $1 only!",
                "Dev.to beats Medium.",
                "We have updated our privacy :/",
                "Nick moves to New Zealand")
        val descriptions = listOf(
                "This is truly amazing, unexpected...",
                "Yes, yes, yes! It is happening!",
                "Follow our blog to learn more...",
                "Well, it supposed to happen...")
        val times = listOf(
                "13:42",
                "16:16",
                "12:34",
                "20:20")
        val emailList = mutableListOf<Email>()
        for (i in 0..10) {
            emailList.add(
                    Email(titles.random(), descriptions.random(), times.random())
            )
        }
        return emailList
    }
}

OMG! Look what we’ve got!!!

result

And now we can Recycle our emails 😜

( ^^)o自自o(^^ )

Top comments (2)

Collapse
 
neokleoys2005 profile image
Giorgos Neokleous

Nice one!

RecyclerView is one of the most important widgets in android development (imo of course!)

One small micro-optimisation, you should fetch the Email object once and not for each field you are populating a widget. Imagine having 44442 emails, it could be fairly expensive. Also the bind method is called quite a lot of times especially if the user is scrolling a lot.

Collapse
 
nickitax profile image
Nick Shulhin • Edited

Thanks a lot for your feedback, Giorgos!!!

I really appreciate it, since do Android exclusively as a hobby which enjoy so much.

I’ll add your fix to the article 👍