Common Mistake Developers Make When Building RecyclerViews and How to Fix It Using “ViewRepresentation” Class

Jermaine Dilao
The Startup
Published in
3 min readAug 16, 2020
https://unsplash.com/photos/DJ7bWa-Gwks

When creating RecyclerView lists, we usually encounter list items that have the same ViewHolder but the values inside it are subject to different conditions.

Let’s say we’re building a list that displays invoices in a card view. Each item in the list has these conditions:

For unpaid invoice:

  1. Displays “Unpaid” label at the top right corner of the card view
  2. Displays “Pay” button at the bottom of the card view
  3. Displays due date in “dd-MM-yyyy” format

For paid invoice:

  1. Displays “Paid” label at the top right corner of the card view
  2. Displays “View” button at the bottom of the card view
  3. Displays due date in “dd-MM-yyyy” format

Let’s use this minimal example just for this article.

Common Mistake

The common mistake I usually notice with some developers is they handle these conditions inside the adapter’s onBindViewHolder() method like this:

private val dateFormatter = SimpleDateFormat("dd-MM-yyyy")
...
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item: Invoice = getItem(position)
if (item.status == PAID) {
holder.status.text = getString(R.string.paid)
holder.button.text = getString(R.string.view)
} else {
holder.status.text = getString(R.string.unpaid)
holder.button.text = getString(R.string.pay)
}

holder.dueDate.text = dateFormatter.format(invoice.dueDate)
}

Surely, this is fine for displaying short lists and for lists that only have those three conditions mentioned above. But, what if we’re displaying hundreds/thousands of items in the list with more conditions?

This would cause onBindViewHolder() to repetitively run those conditions to bind the correct values to the views and the pain point is… poor scrolling performance.

My take on this

As much as possible, the onBindViewHolder’s job should solely be for binding items to the list alone. All the conditions behind the values should be calculated beforehand.

With this in mind, I have come up with this solution.

The “ViewRepresentation” Class

ViewRepresentation is a class that is ready to be bound to the RecyclerView.

This class should already contain the correct values so that the onBindViewHolder()'s job is solely for binding those values to the list.

So, how should this look like using our example?

InvoiceViewRepresentation.kt

So what is this class doing? Let’s break them down below:

  1. It has 3 fields statusText, buttonText, and dueDateText. These three fields should already contain the correct values to be displayed in the list.
  2. fromInvoice() utility method. This method should transform Invoice into its ViewRepresentation equivalent. This is where we run all the necessary conditions and set them ready for the list.

Updated onBindViewHolder() method

Now that we already have our ViewRepresentation class for our Invoice list. Our onBindViewHolder() method should now look like this.

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item: InvoiceViewRepresentation = getItem(position)
holder.status.text = item.statusText
holder.button.text = item.buttonText
holder.dueDate.text = item.dueDateText
}

We have met our goal to make onBindViewHolder()’s only job is to bind the values to the view. That’s how it should be!

We have successfully eliminated repetitively doing the following while scrolling through the list:

  1. Running the if (status == PAID) condition
  2. Calling dateFormatter.format()

And, this should result in a better performant RecyclerView!

And that’s basically it!

I have been using this approach for quite a while now and have no problems with it so far.

Also, it is very convenient especially when the “Invoice” is bound into different screens in your app. You can just reuse the same InvoiceViewRepresentation class and ensure its values are calculated consistently throughout different screens.

I hope this can help someone build better performant lists.

Thank you for reading!

--

--

Jermaine Dilao
The Startup

A Work in Progress Android Developer. You can check me @ https://jermainedilao.github.io/. | 💻 Senior Android Developer @ Speakap