Binding Data to Lists
Binding Data to Lists
In the previous lesson you built the structural scaffolding: a RecyclerView in your layout, a ViewHolder class, and a bare-bones RecyclerView.Adapter. Now the real work begins — supplying a live data set, wiring it to the adapter, and understanding exactly where Android calls your code and why. This lesson focuses entirely on the adapter contract and the patterns a professional Android developer applies to keep UI and data in sync.
Recap: What the Adapter Actually Does
Think of a RecyclerView.Adapter as the bridge between a plain Java list and the rows you see on screen. It answers three questions that the RecyclerView asks repeatedly:
- How many items are there? —
getItemCount() - Create a view holder for this view type. —
onCreateViewHolder() - Bind the data at position N into this holder. —
onBindViewHolder()
All the data-binding logic lives in onBindViewHolder(). Everything else is plumbing.
A Concrete Model Class
Good adapters operate on typed model objects, not raw strings or maps. Define a plain Java model for the items in your list:
Immutable fields with only getters are a safe default for list items — they cannot be accidentally mutated while the adapter is reading them.
A Complete ProductAdapter
Here is a full adapter for a RecyclerView that shows a list of Product objects. Read the inline comments carefully — each line corresponds to a platform rule.
attachToRoot = false? Passing false as the third argument to inflate() tells the inflater to use the parent only for layout parameter context, not to attach the view immediately. RecyclerView manages attachment itself. If you pass true, the view gets attached twice and you see a crash or garbled layout at runtime.
The Corresponding Item Layout
The layout file res/layout/item_product.xml inflated above might look like this:
Wiring the Adapter to the RecyclerView in Your Activity
In your Activity (or Fragment), create the data, instantiate the adapter, and attach it once:
Updating the List: notifyDataSetChanged vs. Targeted Notifications
When your data changes you must tell the adapter. The lazy approach — adapter.notifyDataSetChanged() — works but redraws every visible row even if only one item changed. Android provides surgical alternatives:
notifyItemInserted(int position)— triggers the insert animation for a single row.notifyItemRemoved(int position)— triggers the remove animation.notifyItemChanged(int position)— redraws one row without animation.notifyItemRangeInserted(int positionStart, int itemCount)— efficient bulk insert.
A typical pattern is to expose a method on the adapter that mutates its internal list and fires the correct notification:
notifyDataSetChanged() forces a full redraw and suppresses the default item change animations. Use it only when the entire data set is swapped out. For incremental changes (add one row, delete one row) the targeted methods look far better to the user and are also more efficient.
The Stable IDs Optimisation
If every item in your data set has a unique, persistent identifier (a database primary key, for example), enable stable IDs. This lets RecyclerView track items across data set changes and apply the correct animations even after notifyDataSetChanged():
setHasStableIds(true) without overriding getItemId(). The default implementation returns RecyclerView.NO_ID (-1) for every item, so RecyclerView cannot distinguish between rows, and animations will be incorrect or crash-prone. If you opt into stable IDs, you must provide a genuinely unique value from your model.
What About DiffUtil?
DiffUtil is the production-grade solution for computing the minimal set of changes between two lists and dispatching the exact targeted notifications automatically. It is built on the Myers diff algorithm and runs on a background thread. You will encounter it in real codebases, but it builds directly on the notification APIs you have just learned — master those first. A future lesson in this course covers DiffUtil and ListAdapter in depth.
Summary
Feeding data into a RecyclerView comes down to three moving parts: a typed model class, an adapter that implements the three required callbacks, and a layout manager that tells RecyclerView how to arrange the rows. The binding logic all lives in onBindViewHolder(); keep it fast — no database calls, no heavy computation. When data changes, fire the most targeted notification possible. With these fundamentals in place you are ready to add item click handling and richer row layouts in the lessons ahead.