Rescue View Sanity in RecyclerView!

Pooja Srivastava
Oct 24 · 4 min read

keeping your sanity intact by releasing the view listeners on the holders

Image for post
Image for post
credits: Chetan Garg

In development, we come across various challenges which demand displaying large amounts of data sets that can be scrolled very efficiently without risking the performance cost is where the RecyclerView comes into the picture.

An advanced and flexible version of ListView, that encourages Memory Management by recycling the views as it uses ViewHolder that does the magic in reducing the ViewCreation by keeping the MainThread away from a CPU Intensive Task, thus improving performance.

But since it recycles items, Views that have the toggling behavior (checkbox, switch…etc) end up losing their current state (selected by the user) on scrolling, resulting in unpredictable behavior inside the RecyclerView.

In order to keep the sanity intact of the view, one might be forced to use the Data Structure (like HashMap, SparseBooleanArray… etc), and that’s where my patience starts to run out.

We’ve come far across it so I am gonna show you how I’ve preserved the current state of the checkbox using data classes in Kotlin :

  1. Let’s first create a data class to hold the data
data class ListItem(val checkboxTextValue: String, val checkboxPreviousState: Boolean, var checkboxCurrentState: Boolean = checkboxPreviousState)
  • checkboxPreviousState: holds the state of checkbox prior to user interaction, a val property (read-only boolean variable)
  • checkboxCurrentState: holds the state of the checkbox after the user interaction
    - a var property (you can mutate the state)
    - default initialization with the checkboxPreviousState

2. The Adapter class looks like :

3. The ViewHolder class looks like :

But, a loophole still persists in the ViewHolder class which is :
The ViewHolder entails that the setOnCheckedChangeListener will execute when you click the checkbox but in real — it is firing at a time you’re not expecting.

The ViewHolder that was previously associated with the checked/unchecked checkbox is going to be recycled and then re-used to display another view that might be checked/unchecked. At that point, onBindViewHolder will be called which will trigger

item_checkbox.isChecked =  textListItem.checkboxCurrentState

and ended up triggering the setOnCheckedChangeListener on each item while scrolling down the list, resulting in the changes in the state of views, which were checked previously too.

So, in order to put the situation right, we need to set the state change listener of a checkbox to null as the first thing to prevent the default execution of setOnCheckedChangeListener inside the onBindViewHolder().

Though, to eliminate the scenario we do have several other options — one of them is by calling the click listener of a checkbox rather than listening to the events from setOnCheckedChangeListener.

setOnClickListener will fire the event — only when the checkbox is clicked, unlike setOnCheckedChangeListener which will fire the event every time the checkbox state mutates.

Moving to the next option that we have in a platter is by setting the listener inside the init block — which is another handy option to opt by, but this approach holds the faults of its own as it caches the view references which will turn out to be the prime reason for memory leaks in android.

The references to the previous views won’t be flushed even after the data is refreshed.

Approach 4:

The next one is to release the resources as soon as the view is out of the window in onViewDetachedFromWIndow.

onViewDetachedFromWindow(VH holder) always follows a matching onViewAttachedToWindow(VH holder). It's called in the exact moment when the view holder is becoming visible or invisible (attach or detach calls).

If a viewHolder was detached but not recycled yet, it's possible it can receive onViewAttachedToWindow(ViewHolder) call again without needing to rebind data with onBindViewHolder.

Also, Yes! You can always release the resources in the onViewRecycled(VH holder) method which is called right before clearing ViewHolder’s internal data and sending it to the RecycledViewPool which gives you the benefit of memory recollection by dumping the cached data consumed by the resources.

Well, it is highly recommended — If an item view has large or expensive data bound to it such as large bitmaps, this may be a good place to release those resources.

Conclusion

With these solutions, I have eliminated the possible holes that could become a pain for the app. I had encountered the same scenario which leads me to come up with these resolutions, though the door’s always open to exploring for more.

For just a simple view like this, I’d rather recommend you use any of the above approaches but the fifth one would be a reliable solution in case of the complex views too.

I hope that reading this will be as useful for you as writing it was for me. The link to the project has been added below.
This is my very first technical article on Medium after being motivated by my colleague who is blessedly good at coding. Chetan Garg helped me out during my findings and if you wanna dive deep into Kotlin, read his articles.

Stay Safe… Enjoy Life & Keep Coding!

The Startup

Medium's largest active publication, followed by +730K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store