RecyclerView & Lists
Why RecyclerView?
Showing a list of 1,000 items by creating 1,000 views would freeze the app and run out of memory. RecyclerView solves this by keeping only the few rows visible on screen and recycling them as you scroll — when a row scrolls off the top, it’s reused for a new row at the bottom.
The four pieces
- Data — your list of items.
- Row layout — an XML file describing one row.
- ViewHolder — holds references to a row’s views so they aren’t looked up repeatedly.
- Adapter — creates ViewHolders and binds data to them.
A modern adapter with ListAdapter + DiffUtil
ListAdapter uses DiffUtil to figure out exactly what changed and animate it — no manual notifyDataSetChanged().
data class User(val id: Int, val name: String)
class UserAdapter : ListAdapter<User, UserAdapter.VH>(Diff) {
object Diff : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(a: User, b: User) = a.id == b.id
override fun areContentsTheSame(a: User, b: User) = a == b
}
class VH(val b: ItemUserBinding) : RecyclerView.ViewHolder(b.root)
override fun onCreateViewHolder(parent: ViewGroup, type: Int): VH {
val b = ItemUserBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return VH(b)
}
override fun onBindViewHolder(holder: VH, position: Int) {
holder.b.name.text = getItem(position).name
}
}
Wiring it up
val adapter = UserAdapter()
binding.recycler.layoutManager = LinearLayoutManager(this)
binding.recycler.adapter = adapter
adapter.submitList(listOf(User(1, "Anand"), User(2, "Priya")))
Handling clicks
Pass a lambda into the adapter and call it from onBindViewHolder — never give each row its own heavy listener logic.
Common mistakes
- Calling
notifyDataSetChanged()for everything — prefersubmitList()with DiffUtil. - Forgetting to set a
LayoutManager(the list shows nothing). - Doing image loading on the main thread inside
onBindViewHolder— use a library like Coil.
Summary: RecyclerView recycles rows for performance. UseListAdapter+DiffUtil+submitList()for clean, animated updates.