Doing Android Long Lists Effectively
Tags: recyclerview, adapter, listadapter, android
Published: 2019-12-16 19:21:47

---
title: Doing Android Long Lists Effectively
published: true
description: When you've got to have a long list of items in Android how do you handle them well?
tags: recyclerview, adapter, listadapter, android
---

You're going to need a RecyclerView no doubt, but making the right choice of adapter can reduce your work tremendously and set you up for success.

If you aren't ever going to change the items in a list while the user's looking at them, this article won't matter to you. But if you are, this will be the simplest, nicest animating, easiest to reason about implementation of it you'd have ever seen.

Normally you'd choose a [Recyclerview.ViewHolder](https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.ViewHolder.html) but in almost all cases involving changing lists, you're better off choosing the [ListAdapter](https://developer.android.com/reference/androidx/recyclerview/widget/ListAdapter.html) 

The key difference between the two, is that the ListAdapter includes an easy way to notify which items have changed by giving us a nearly complete implementation of the [DiffUtil.ItemCallback](https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil.ItemCallback).

Normally, implementing this involves a bit of boilerplate but the ListAdapter abstracts all that out for you.

This handles all the complicated diffing code and you can just focus on providing up-to-date lists of data via sending them to the ListAdapter method
```java
public void submitList(@Nullable List<T> list)
```

So now all you've got to implement are:

`onCreateViewHolder`, `onBindViewHolder`, and the DIFF_CALLBACK.

Then when you have a different list, send it to the `adapter.submitList(list)`.

The first two are standard functions, so their implementation is left as an exercise to the reader.

However, we'll be focusing on the DIFF_CALLBACK. Here's the relevant section:

ListAdapter takes ones of these as a constructor parameter.

Creating a static version of it is great because the interface is built to abstract over comparing two instances at a time, and these are always passed in.

The implementation has two functions, one meant to be a lightweight comparison `areItemsTheSame` this should be an id or a field that will be compared.
`areContentsTheSame` does a deep comparison and checks if the objects are exactly the same.
This speeds up comparisons between objects because if they're not the same, a deep comparison doesn't have to be done at all.

I wish the [official docs](https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil.ItemCallback.html#areContentsTheSame(T,%20T)) made it a bit clearer!

Here's what that looks like:


```kotlin
class AstronomyPicListAdapter : ListAdapter<AstronomyPic, ApodDetailViewHolder>(DIFF_CALLBACK) {

    companion object { // We create a static version since this doesn't keep state, it only compares the instances it's passed as function parameters.
        val DIFF_CALLBACK = object : DiffUtil.ItemCallback<AstronomyPic>() {
            override fun areItemsTheSame(oldItem: AstronomyPic, newItem: AstronomyPic): Boolean =
                oldItem.date == newItem.date

// Usually a deep comparison.
            override fun areContentsTheSame(oldItem: AstronomyPic, newItem: AstronomyPic): Boolean =
                oldItem == newItem

        }
    }

// Standard oncreateViewHolder using Databinding
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ApodDetailViewHolder {
        return ApodDetailViewHolder(
            DataBindingUtil.inflate<DetailListApodItemBinding>(
                LayoutInflater.from(parent.context),
                R.layout.detail_list_apod_item,
                parent,
                false
            )
        )
    }

// Standard bindViewHolder that uses a bind method and only passes in the data if it was non-null
    override fun onBindViewHolder(holder: ApodDetailViewHolder, position: Int) {
        getItem(position)?.let { holder.bind(it) }
    }


}

```

## What this does for you:
1. You now only have to get a new list and 'submit' it to the adapter.
2. The adapter calculates what values have actually changed.
3. And calls notifyItemChanged on only those specific values.

This results in:
1. Better animations
2. Less work for you
3. Never having to think about notifyItemChanged or dread telling the recyclerview that all times have changed!