Picasso: Picasso + RecyclerView + StaggeredGridLayoutManager shuffles resizable recycler views infinitely

Created on 5 Mar 2015  ·  15Comments  ·  Source: square/picasso

Example Project: https://github.com/pohh/slotmachinepicasso

Bug In Action:
https://github.com/pohh/slotmachinepicasso/blob/master/slotmachine.mp4

1:02 - slight jitter
1:20 - slot machine shuffle

In low memory situations, the interaction between Picasso and the StaggeredGridLayoutManager causes the views to go into a slot machine shuffle, where each span is continuously recycling views.

When scrolling upwards, the way Picasso populates ImageView from cache misses interferes with StaggredGridLayoutManager's calculations.

To mimic the low memory situation we are seeing in our app, I purposely set the LRU cache to a small number.

This bug is difficult to reproduce on Nexus 5 running Android L (although it is reproducible). I have had the best luck reproducing on the galaxy S3,S4,S5.

Most helpful comment

@yuvaraj119 thanks very much for explanation. In the meantime i found another solution to fix my problem about the stutter :

    recyclerView.setHasFixedSize(true);
    recyclerView.setItemViewCacheSize(20);
    recyclerView.setDrawingCacheEnabled(true);
    recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);

setting these values to RecyclerView solved my stutter problem. Hope it helps someone else too ;)

also thanks to @JakeWharton , his comment redirected me to right direction.

Picasso rules :D

All 15 comments

Additionally I have tried using the resize() method and fit() and center(), but to no effect. The slot machine effect still occurs.

I'm having a hard time seeing how Picasso is the cause of the problem. I would imagine it's your DynamicHeightImageView allowing the relayout to happen when setImageDrawable is called by Picasso which triggers the pathalogical re-layout of the entire recycler view.

I submitted the issue on both google issue tracker and created this issue to get some eyes on the implementation and perhaps point out any errors in usage of either library.

I was able to force the issue to occur consistently when I lowered the Picasso cache size, so I was wondering if there was something in the Picasso caching functionality that could be making the behaviour occur more, but I would tend to agree that Picasso is not the likely root cause here. My current theory was that due to the image resize, the SGLM enters a state where it flags a span as invalid, triggers a refresh, and is unable to unflag the span as invalid.

@JakeWharton do you have any recommendations on a proper integration of Picasso + RecyclerView/StaggeredGridLayout with varying image sizes and placeholders which match those image sizes?

This question may be better directed at the Google team, but can you explain why setImageDrawable would force another layout? My intention with DynamicImageView is to already have the view at the drawable dimension prior to the setImageDrawable call, specifically to avoid causing another layout pass. Is the implementation of the DynamicImageView incomplete?

Setting an image causes ImageView to relayout to fit the Drawables
intrinsic bounds.

I submitted the issue on both google issue tracker and created this issue
to get some eyes on the implementation and perhaps point out any errors in
usage of either library.

I was able to force the issue to occur consistently when I lowered the
Picasso cache size, so I was wondering if there was something in the
Picasso caching functionality that could be making the behaviour occur
more, but I would tend to agree that Picasso is not the likely root cause
here. My current theory was that due to the image resize, the SGLM enters a
state where it flags a span as invalid, triggers a refresh, and is unable
to unflag the span as invalid.

@JakeWharton https://github.com/JakeWharton do you have any
recommendations on a proper integration of Picasso +
RecyclerView/StaggeredGridLayout with varying image sizes and placeholders
which match those image sizes?

This question may be better directed at the Google team, but can you
explain why setImageDrawable would force another layout? My intention with
DynamicImageView is to already have the view at the drawable dimension
prior to the setImageDrawable call, specifically to avoid causing another
layout pass. Is the implementation of the DynamicImageView incomplete?


Reply to this email directly or view it on GitHub
https://github.com/square/picasso/issues/918#issuecomment-77671009.

Hi, did you find the root cause of the problem? I had the same issue and with the help of your DynamicHeightImageView class and the fit() method it seems to works expect a minor problem which is maybe not related.

I was not able to find a root cause. From what I recall the staggered grid layout manager at the time had some issues, it seems to have calmed down recently. A good first step may be to look at the delta in the support library impelementations of staggered grid layout manager between 21.0.3 and now.

hi pohh i have fixed this issue with some changes and thanks for this project.
the updated code is here.
https://github.com/yuvaraj119/Picasso-RecyclerView-StaggeredGridLayoutManager
the issue is not with Picasso library

@yuvaraj119 would you explain how did you solve the problem?

Yes, by setting the RelativeLayout params with height and width to imageview in onBindViewHolder, issue is because of when you move from top to bottom or vice versa the recyclerview will not remember the width and height of imageview.

@Override public void onBindViewHolder(ViewHolder viewHolder, int position) { MyViewHolder vh = (MyViewHolder) viewHolder; ImageModel item = imageModels.get(position); RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams) vh.imageView.getLayoutParams(); float ratio = item.getHeight() / item.getWidth(); rlp.height = (int) (rlp.width * ratio); vh.imageView.setLayoutParams(rlp); vh.positionTextView.setText("pos: " + position); vh.imageView.setRatio(item.getRatio()); Picasso.with(mContext).load(item.getUrl()).placeholder(PlaceHolderDrawableHelper.getBackgroundDrawable(position)).into(vh.imageView); }

@yuvaraj119 thanks very much for explanation. In the meantime i found another solution to fix my problem about the stutter :

    recyclerView.setHasFixedSize(true);
    recyclerView.setItemViewCacheSize(20);
    recyclerView.setDrawingCacheEnabled(true);
    recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);

setting these values to RecyclerView solved my stutter problem. Hope it helps someone else too ;)

also thanks to @JakeWharton , his comment redirected me to right direction.

Picasso rules :D

Thanks for sharing @ergunkocak

confirming that @ergunkocak solution works, thanks

Thanks very much

@yuvaraj119 thanks very much for explanation. In the meantime i found another solution to fix my problem about the stutter :

    recyclerView.setHasFixedSize(true);
    recyclerView.setItemViewCacheSize(20);
    recyclerView.setDrawingCacheEnabled(true);
    recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);

setting these values to RecyclerView solved my stutter problem. Hope it helps someone else too ;)

also thanks to @JakeWharton , his comment redirected me to right direction.

Picasso rules :D

It works♥️

Was this page helpful?
0 / 5 - 0 ratings