RecyclerView Optimization - Scrolling Performance Improvement

Banner Recyclerview Optimization Scrolling Performance Improvement

In this blog, we are going to learn how to optimize the RecyclerView performance in Android. With these optimizations, we can make the RecyclerView scrolling smooth.

When we implement RecyclerView in our Android Application, sometimes, we face problems like: The RecyclerView items are not scrolling smoothly. It leads to bad user experience as it seems that our Android App is laggy.

Let's see what are the things which we can do to improve the performance of the RecyclerView and hence, we get the smooth scrolling.

RecyclerView Optimization Techniques

Let's get started

Use Image-Loading Library

As the Garbage Collection(GC) runs on the main thread, one of the reasons for unresponsive UI is the continuous allocation and deallocation of memory, which leads to the very frequent GC run. By using the bitmap pool concept, we can avoid it.

The best part is that Image-Loading libraries like Glide, Fresco uses this bitmap pool concept. So, always use Image-Loading libraries.

Delegate all the image-related tasks to these libraries.

If you are curious to know: How The Android Image Loading Library Glide and Fresco Works? Read here.

Set Image Width and Height

If our image width and height are dynamic(not fixed), and we are getting the imageUrl from the server.

If we do not set the correct image width and height prior, the UI will flicker during the transition of loading(downloading of image) and setting of the image into the ImageView(actually making it visible when downloading completes).

So, we should ask our backend developer to send the image size or the aspect ratio, accordingly, we can calculate the required width and height of the ImageView.

Then, we will be able to set the width and height prior only. Hence no flickering. Problem Solved!

Do less in onBindViewHolder method

Our onBindViewHolder method should do very less work. We should check our onBindViewHolder method and optimize it. We can see the improvement in our RecyclerView by doing so.

Use Notify Item RecyclerView API

Whenever we have the use-case of the removal, the updation, the addition of item, use the Notify Item API.

adapter.notifyItemRemoved(position)
adapter.notifyItemChanged(position)
adapter.notifyItemInserted(position)
adapter.notifyItemRangeInserted(start, end)

Also, check DiffUtil.

In case, we are forced to use notifyDataSetChanged() based on our use-case, we can try the setHasStableIds(true).

adapter.setHasStableIds(true)

It indicates whether each item in the data set can be represented with a unique identifier of type Long.

Even if we call the notifyDataSetChanged(), it does not have to handle the complete re-ordering of the whole adapter because it can find if the item at a position is the same as before and do less work.

Avoid a nested view

If possible, we should avoid a nested view and try to create a flat view wherever possible. Nesting reduces RecyclerView performance. Flat View improves performance.

Use setHasFixedSize

We should use this method if the height of all the items is equal. Add the below and check the performance.

recyclerView.setHasFixedSize(true)

Use setRecycledViewPool for Optimizing Nested RecyclerView

As we know that the RecyclerView works on the principle of "Reuse View Using Pool" wherever possible.

Check How does RecyclerView work internally?

If we have the use-case of Nested RecyclerView.

- OuterRecyclerView
    - InnerRecyclerViewOne
    - InnerRecyclerViewTwo

But by default, the optimization works for that particular RecyclerView because that particular RecyclerView has its own View Pool.

The pool does not get shared between two RecyclerViews having the same types of views.

So, what we can do is that we can create a single ViewPool and pass it to all the inner RecyclerViews so that it gets shared like below:

class OuterRecyclerViewAdapter() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    // code removed for brevity

    private val viewPool = RecyclerView.RecycledViewPool()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {

        // code removed for brevity
        
        viewHolderOne.innerRecyclerViewOne.setRecycledViewPool(viewPool)
        
        // code removed for brevity

        viewHolderTwo.innerRecyclerViewTwo.setRecycledViewPool(viewPool)
        
    }
    
    // code removed for brevity
}

This will improve scrolling performance as it will start reusing the view from the shared ViewPool.

Use setItemViewCacheSize

We can experiment by setting the ItemView Cache Size.

recyclerView.setItemViewCacheSize(cacheSize)

As per the official documentation: It sets the number of offscreen views to retain before adding them to the potentially shared recycled view pool. The offscreen view cache stays aware of changes in the attached adapter, allowing a LayoutManager to reuse those views unmodified without needing to return to the adapter to rebind them.

It means that when we scroll the RecyclerView such that there's a view that is just barely completely off-screen, the RecyclerView will keep it around so that we can scroll it back into view without having to call the onBindViewHolder() again.

Generally, we do not change the size of the View Cache, but experiment with it, if it works for you, implement it.

These are things which we can do to improve the performance of RecyclerView. That's it for now.

Happy Learning :)

Amit Shekhar

Co-Founder, MindOrks

Show your love by sharing this blog with your fellow developers.