RecyclerView, ViewBinding, ConstraintLayout — performance
RecyclerView is the standard for large lists — its essence is view recycling: an item scrolled off screen returns its view to a pool for reuse (onBindViewHolder only binds data, no inflation).
Key parts:
- ViewHolder — caches view references, avoiding repeated
findViewById - DiffUtil / ListAdapter — diffs old/new lists and updates only changed items; bare
notifyDataSetChanged()is the expensive antipattern - ItemDecoration / ItemAnimator — dividers and animations
ViewBinding generates a type-safe binding class per layout: no findViewById, null-safe, and unlike DataBinding it puts no logic in layouts (DataBinding expressions are discouraged in modern code).
ConstraintLayout — complex layouts with a flat hierarchy: it avoids the double measure passes nested LinearLayouts (especially with layout_weight) cause. Deep view hierarchies = slow measure/layout = dropped frames.
class TransactionAdapter :
ListAdapter<TransactionUi, TransactionAdapter.VH>(Diff) {
object Diff : DiffUtil.ItemCallback<TransactionUi>() {
override fun areItemsTheSame(a: TransactionUi, b: TransactionUi) = a.id == b.id
override fun areContentsTheSame(a: TransactionUi, b: TransactionUi) = a == b
}
class VH(val binding: ItemTransactionBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = VH(
ItemTransactionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
)
override fun onBindViewHolder(holder: VH, position: Int) {
val item = getItem(position)
holder.binding.title.text = item.title
holder.binding.amount.text = item.formattedAmount
}
}
// İstifadə: adapter.submitList(newList) — diff arxa planda hesablanırListAdapter + DiffUtil — the modern list adapter
A frame for the performance question: (1) lists — ListAdapter/DiffUtil, setHasFixedSize(true), simpler item layouts, Coil/Glide for images (placeholder + sizing); (2) hierarchy — check depth in Layout Inspector, move to ConstraintLayout, use merge/ViewStub; (3) measurement — Profiler + Choreographer frame metrics. "What must onBindViewHolder never do?" — allocate objects, load images synchronously, re-wire listeners per bind.
🛠 Practice task
Build a list of 50+ items and measure three changes:
- Update it with
notifyDataSetChanged()first, then withListAdapter+DiffUtil(submitList) — observe the animation and smoothness difference. - Allocate an object inside
onBindViewHolderon purpose and watch allocations in the Profiler; then clean it up. - Check the item layout's depth in Layout Inspector and flatten a nested
LinearLayoutintoConstraintLayout.
Done when: you can answer "the list is janky" with a measure → fix → measure story.
📚 Sources and documentation
- Create dynamic lists with RecyclerViewofficialdeveloper.android.com
- View bindingofficialdeveloper.android.com
- ConstraintLayoutofficialdeveloper.android.com