RecyclerView Trick: Selectively bind ViewHolders with Payloads

What if you want to update a single item in a RecyclerView but don’t want to rebind the entire view? There’s actually a variation of notifyItemChanged that allows us to do just that:

Before:

Consider this example click handler for a RecyclerView item:

After the call to notifyItemChanged, the adapter gets notified and onBindViewHolder gets called. Unfortunately, rebinding the entire view can lead to some visual quirks*:

GOTCHA!! When we notify our adapter that an item has changed, the entire view gets rebound, causing a flash on the view’s image.

What if we only want to update the parts of the view that actually changed? When we notify our adapter, we can pass along a “payload” object:

Then we add logic to our adapter to handle these special “payloads”:

After:

Viola!! Only the favorite icon changes:

This strategy has a few advantages:

  1. We keep all of our view binding logic contained inside of our Adapter classes.
  2. We have flexible options about how to bind: only want to bind certain parts of the View? Sure. Want animations to show the change, but only on certain updates? Yup. Want to chain together multiple calls to notifyItemChanged to reflect multiple updates? You betcha, onBindViewHolder will give you an entire List<Object> that has all of your payloads merged together.
  3. We can always fallback to a default update; any time the adapter doesn’t know how to handle a certain payload, the view gets fully rebound.

Happy recycling!

*The background flash is actually intended behavior and occurs because of DefaultItemAnimator's implementation of the “change” animation. Calling setSupportChangeAnimations(false) would also “fix” the background flash. This solution is a bit heavy handed, however. Disabling change animations on the ItemAnimator will stop all animations when often times we only want to disable some animations.

Andrew writes code with Livefront and plays guitar in his free time.