RecyclerView & Lists
RecyclerView & Lists
Every real Android application displays lists: a feed of messages, a catalogue of products, a history of transactions. The widget designed for this job is RecyclerView. It replaced the older ListView because it solves two hard problems at once: it recycles the view objects that scroll off screen rather than destroying and recreating them, and it imposes no constraints on how items are arranged or animated. Understanding how RecyclerView works — and why it is structured the way it is — will make you a more effective Android developer across every feature you build.
Why RecyclerView Exists
Imagine displaying 10,000 contacts. Inflating 10,000 View objects at once would consume hundreds of megabytes of memory and freeze the UI thread. RecyclerView solves this by maintaining a small pool of view objects — typically only slightly more than the number visible on screen — and recycling them as the user scrolls. When a row scrolls off the top, its view is detached from the window and placed back in the pool. When a new row needs to appear at the bottom, a pooled view is retrieved, its contents are overwritten with the new data, and it is attached to the window.
RecyclerView never inflates more view objects than it needs to fill the screen. Your data set can have a million items; the memory footprint for the list UI stays constant.
The Three-Part Architecture
RecyclerView is intentionally split into three separate collaborating objects, each with a single responsibility:
- RecyclerView — the
ViewGroupthat goes in your layout XML. It manages the item pool, handles touch events, and orchestrates scrolling. - LayoutManager — decides where to position items.
LinearLayoutManagergives you a vertical or horizontal list;GridLayoutManagergives you a grid;StaggeredGridLayoutManagergives you Pinterest-style unequal rows. - Adapter — bridges your data and the view pool. It inflates new view holders when the pool is empty, and binds fresh data into a recycled view holder when one is needed.
Adding RecyclerView to Your Layout
First, add the dependency to your build.gradle (app module). In modern projects it usually arrives via the appcompat or material dependency, but you can also declare it directly:
Then place it in your activity layout:
Defining the Item Layout
Each row needs its own layout file. Create res/layout/item_contact.xml:
The Model Class
A simple plain Java object to hold the data for one row:
Building the Adapter and ViewHolder
This is where the real work happens. The Adapter has three responsibilities, expressed as three methods you must override:
onCreateViewHolder— inflate the item layout and wrap it in aViewHolder. Called only when the pool has no recycled holder available.onBindViewHolder— take a recycled (or freshly created) holder and populate it with the data at a given position. Called every time a row is about to appear on screen.getItemCount— tell theRecyclerViewhow many items exist.
The ViewHolder is an inner class that caches the View references for one row. Without it, every call to onBindViewHolder would have to call findViewById on the root view — an expensive tree traversal — on every single scroll event.
onBindViewHolder fast. It runs on the UI thread and is called for every row that enters the viewport during scrolling. No network calls, no disk I/O, no complex computation here — only data reads and setText / setImageBitmap style calls. Anything heavier belongs in a background thread before this point.
Wiring Everything Together in the Activity
Three lines do all the work: set a LayoutManager (vertical list by default), create the adapter with the data, and assign it. RecyclerView will immediately ask the adapter how many items exist and start inflating and binding as needed.
Updating the List Efficiently
Calling notifyDataSetChanged() forces a full rebind of every visible row — it works, but it skips item-change animations and is wasteful. Prefer the targeted notification methods when you know exactly what changed:
onBindViewHolder on the UI thread. A concurrent write from another thread will cause a crash or produce stale visuals. Always perform list mutations on the main thread, or use DiffUtil (covered in the next lesson) which hands the final swap back to the main thread safely.
Handling Item Clicks
Unlike ListView, RecyclerView has no built-in click listener. The idiomatic pattern is to pass a callback interface into the adapter:
Pass a lambda from the activity: new ContactAdapter(contacts, contact -> openDetail(contact)). This keeps the adapter free of any knowledge of navigation or business logic.
Summary
RecyclerView is built on three objects working together: the widget itself, a LayoutManager that places items, and an Adapter that inflates and binds them. The ViewHolder pattern is mandatory — it caches findViewByid lookups so that onBindViewHolder stays fast during scrolling. Structuring click handling as a callback interface keeps the adapter focused and testable. In the next lesson you will replace the static list with live data fetched from a database or network, and learn how DiffUtil computes minimal updates automatically.