Android Recyclerview Scrolling Performance

Android RecyclerView Scrolling Performance

I've recently faced the same issue, so this is what I've done with the latest RecyclerView support library:

  1. Replace a complex layout (nested views, RelativeLayout) with the new optimized ConstraintLayout. Activate it in Android Studio: Go to SDK Manager -> SDK Tools tab -> Support Repository -> check ConstraintLayout for Android & Solver for ConstraintLayout. Add to the dependencies:

    compile 'com.android.support.constraint:constraint-layout:1.0.2'
  2. If possible, make all elements of the RecyclerView with the same height. And add:

    recyclerView.setHasFixedSize(true);
  3. Use the default RecyclerView drawing cache methods and tweak them according to your case. You don't need third party library to do so:

    recyclerView.setItemViewCacheSize(20);
    recyclerView.setDrawingCacheEnabled(true);
    recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
  4. If you use many images, make sure their size and compression are optimal. Scaling images may also affect the performance. There are two sides of the problem - the source image used and the decoded Bitmap. The following example gives you a hint how to decode аn image, downloaded from the web:

    InputStream is = (InputStream) url.getContent();
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inPreferredConfig = Bitmap.Config.RGB_565;
    Bitmap image = BitmapFactory.decodeStream(is, null, options);

The most important part is specifying inPreferredConfig - it defines how many bytes will be used for each pixel of the image. Keep in mind that this is a preferred option. If the source image has more colors, it will still be decoded with a different config.


  1. Make sure onBindViewHolder() is as cheap as possible. You can set OnClickListener once in onCreateViewHolder() and call through an interface a listener outside of the Adapter, passing the clicked item. This way you don't create extra objects all the time. Also check flags and states, before making any changes to the view here.

    viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
    Item item = getItem(getAdapterPosition());
    outsideClickListener.onItemClicked(item);
    }
    });
  2. When data gets changed, try to update only the affected items. For example instead of invalidating the whole data set with notifyDataSetChanged(), when adding / loading more items, just use:

    adapter.notifyItemRangeInserted(rangeStart, rangeEnd);
    adapter.notifyItemRemoved(position);
    adapter.notifyItemChanged(position);
    adapter.notifyItemInserted(position);
  3. From Android Developer Web Site :

Rely on notifyDataSetChanged() as a last resort.

But if you need to use it, maintain your items with unique ids:

    adapter.setHasStableIds(true);

RecyclerView will attempt to synthesize visible structural change
events for adapters that report that they have stable IDs when this
method is used. This can help for the purposes of animation and visual
object persistence but individual item views will still need to be
rebound and relaid out.

Even if you do everything right, chances are that the RecyclerView is still not performing as smoothly as you would like.

RecyclerView scrolling laggy on newer android versions

I solved the problem by setting the build variant to release after finding this comment: Performance of ConstraintLayout inside RecyclerView ViewHolder.

The example shared here is smoothly then and my application with Glide performs more smoothly, too, even without setting layout_width to ConstraintLayout.

But it's unclear to me why this lag appears in the debug mode and only on the latest android versions.

How to Improve image Scrolling performance in recyclerview (app lagging during scroll in recyclerview)?

Use the recycler-view cache this will help you

recyclerView.setItemViewCacheSize(25);
recyclerView.setDrawingCacheEnabled(true);
recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);

Use fit()

Picasso.with(context)
.load(Uri.parse(String.valueOf(albumArtUri)))
.resize(200,200)
.fit()
.centerCrop()
.into(image);

The fit() actually resizes the image to fit into the imageView's bounds. This doesn't load the full image and smooth the scrolling.

Recyclerview lagging in scrolling

Try to use image-loading libraries like Glide, Picasso, Coil. They can load images on background threads.

Android: Jank on initial scroll with RecyclerView in debug

I'll post this as an answer since it does what I require - it reduces the time the first scroll takes.

I moved pre-creation of the two types of view holders in the calling activity:

for (i in 1..30) {
val v = LayoutInflater.from(parent.context).inflate(R.layout.wallpost_view, parent, false) as LinearLayout
val viewHolder = MyViewHolder(v, context, nestedViewsPool)
viewHolders.push(viewHolder)
}

for (i in 1..20) {
val v = LayoutInflater.from(this).inflate(R.layout.comment_view, null) as LinearLayout
val viewHolder = WallpostsListAdapter.CommentsViewHolder(v)
adapter.commentViewHolders.push(viewHolder)
}

This made the first scroll arround 2 times faster in most of the tests I conducted. And this action lead to the biggest gain in the optimization process.

I also adopted part of @Fabio's suggestions:

1. As I stated in the comments, I measure that stuff in debug mode to
be able to better see the optimization results. In release, of
course, the numbers in milliseconds will be much smaller (actually
arround 10 times smaller from what I saw in the systrace in
release).

2. This was the point that made the biggest difference, not huge
difference but still it could be spotted in systrace. Check pastebins in the end of the answer for more info.

3. Indeed, Google recommends using ContraintLayout instead of nested
layouts, but in my case this didn't make any difference. Actually
nested linear layouts seemed to show slightly better resutls.
My
guess is that the views are not complex enough to see the gain with
CL. I couldn't test the final optimized code with nested linear
layouts, because I now use single multi-type view RV and they
weren't working correctly with it, couldn't find the reason, but
probably the gain wouldn't have been that significant.

4. Good point, but it didn't make any signifcant difference in my case, at least.

5. Obsolete as there is now only a single RV without nesting.

Relevant code

  • RV's adapter - now a multi-type view adapter, managing both
    posts and comments. The biggest change was that I needed to write
    mapping code between RV position and array index. Now on init I need
    to do that mapping. In comment's VH binding, I first need to get
    their parent post's RV position, from there the index in the array
    and finally from their difference to get the comment's index within
    post's comments array.
  • Post's view with ConstraintLayout
  • Comment's view with CL

Systraces

  • Views with CL, all view holders pre-created, single RV - here
  • Views with CL, only post's VH pre-created, single RV - here

Strategies for displaying large dataset in Android RecyclerView

consider android's paging library

It works in terms of loading data as pages and not just loading everything into memory. When scrolling, it'll load the appropriate pages you tell it to, so it wouldn't have to keep everything in memory, you could pass in appropriate keys for where to retrieve data and the pagination library will handle that for you.

It supports reading from a database as well as to read from the network or a hybrid of the two, so it should be fine for whichever you need


I suppose it's worth saying that, if you already have your own implementation going, you could also try to mimic this behavior. If you have a way of knowing that a user has reached a certain threshold within the data you're displaying, you could load the next/previous page yourself, then just manage the amount of data you keep in memory yourself. one page up/down might be sufficient, anything more you could clear out your own local memory



Related Topics



Leave a reply



Submit