RecyclerView, DiffUtil & XML Layouts Quiz

UI › Views & RecyclerView

Which component stores scrapped ViewHolders so they can be reused instead of re-inflated?

Answer: The RecycledViewPool

Offscreen ViewHolders are scrapped into the RecycledViewPool, keyed by view type. When a new item scrolls in, RecyclerView rebinds a pooled holder instead of inflating a new one.

Your list updates by calling notifyDataSetChanged() after every change. What is the main cost?

Answer: Every visible holder is rebound and item animations are lost

notifyDataSetChanged() invalidates everything: all visible items rebind, and RecyclerView can't tell what moved, so it can't animate or skip work. Views are still recycled (not necessarily re-inflated), but the granular notify/DiffUtil path does strictly less work.

In a DiffUtil callback, an old and new entry return true from areItemsTheSame() and false from areContentsTheSame(). What does RecyclerView do?

Answer: Rebinds that item (a change, optionally with a payload)

Same identity + different contents = a changed item. RecyclerView dispatches a change notification for it, and getChangePayload() can narrow the rebind to just the changed part.

What is the purpose of getChangePayload() in DiffUtil?

Answer: Describe what changed so onBindViewHolder can do a partial rebind

The payload flows into onBindViewHolder(holder, position, payloads). Instead of rebinding the whole row you can update only the field that changed, e.g. a like count, avoiding image reloads and text relayout.

Where should an item's click listener be attached, and how should it find the clicked item?

Answer: In onCreateViewHolder, reading bindingAdapterPosition when the click fires

Attaching once at create time avoids allocating a new listener on every bind. Reading bindingAdapterPosition at click time keeps it correct after moves; a position captured at bind time can be stale.

Why must bindingAdapterPosition be checked against RecyclerView.NO_POSITION before use?

Answer: The holder may be clicked mid-update, after its item was removed

During updates and animations a holder can be detached from any adapter position (e.g. its item was just removed). Using -1 (NO_POSITION) as an index would crash or act on the wrong item.

What is the recommended way to add equal spacing between all items in a list?

Answer: An ItemDecoration overriding getItemOffsets()

getItemOffsets() adds space outside each item without touching the item layout. It can vary by position (e.g. no top gap for the first row), composes with other decorations, and is reusable across screens.

Why do nested LinearLayouts with layout_weight hurt measure performance?

Answer: Weights force extra measure passes that multiply with nesting (double taxation)

A weighted LinearLayout measures children once to get desired sizes and again to distribute remaining space. Nest two of them and the inner children get measured 4 times; each level multiplies. In a list row this happens for every bound item.

What does the <merge> tag do in an XML layout?

Answer: Removes a redundant wrapper ViewGroup when the layout is included in a parent

When a <merge> root is inflated into a parent (via <include> or a custom ViewGroup inflating itself), its children attach directly to that parent, eliminating one level of nesting that would otherwise exist just to satisfy the single-root rule.

When is ViewStub the right tool?

Answer: For rarely-shown UI, so its subtree is only inflated on first use

A ViewStub is a zero-size placeholder; calling inflate() (or setting it visible) swaps in the real layout. Error banners, empty states and other sometimes-UI cost nothing until actually needed.

Where does ListAdapter (AsyncListDiffer) run the diff computation triggered by submitList()?

Answer: On a background thread, then applies updates on the main thread

The Myers diff can be O(N) to O(N^2)-ish work; AsyncListDiffer moves it off the main thread and posts the resulting granular notifications back, so large list swaps don't jank the frame.

What does recyclerView.setHasFixedSize(true) actually promise?

Answer: The RecyclerView's own size won't change when adapter contents change

It is about the RecyclerView's dimensions, not item sizes: if adapter changes can't resize the RecyclerView (e.g. it is match_parent), it can skip requesting layout on its parent when items change, saving a layout pass.

Which of these in onBindViewHolder is the classic scroll-jank mistake?

Answer: Creating a SimpleDateFormat and formatting a date on every bind

Bind runs for every row as you fling; per-bind allocations (formatters, listeners, bitmaps) and CPU-heavy work multiply into dropped frames. Precompute display strings in the model/mapper, or cache formatters.

A vertical list contains horizontal carousels (RecyclerView inside RecyclerView). What is the standard optimisation?

Answer: Share one RecycledViewPool across the inner lists

Each inner RecyclerView otherwise keeps its own pool, re-inflating carousel cells as rows recycle. A shared pool lets a scrolled-away row's cells be reused by the next row's carousel. Also set the inner LinearLayoutManager's recycleChildrenOnDetach.

Back to RecyclerView, DiffUtil & XML Layouts