UIL, Picasso - Images in adapter always reload when stop scrolling
Asked Answered
R

2

11

I have ListView with text and large image from internet. My image item has fit width and wrap_content height.
I tried to display image in background with UIL & Picasso. Both of them can work but the image always reloads when I stop scrolling, and it makes ListView flickering
It looks like this:

enter image description here

You can see that it reload downloaded and cached images when I stop scrolling (I scroll down and then scroll up).
How can I prevent this happen?

 <ImageView android:id="@+id/imgFeed"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:scaleType="centerCrop"/>

 // UIL
 options = new DisplayImageOptions.Builder()
 .showImageOnLoading(defaultImage)
 .showImageOnFail(defaultImage)
 .showImageForEmptyUri(defaultImage)
 .resetViewBeforeLoading(false)
 .cacheOnDisk(true).delayBeforeLoading(0)
 .displayer(new  FadeInBitmapDisplayer(200)).cacheInMemory(true).imageScaleType(ImageScaleType.EXACTLY_STRETCHED).build();

 ImageAware imageAware = new ImageViewAware(viewHolder.imgFeed, false); 
 ImageLoader.getInstance().displayImage(item.getPhotoUrl(), imageAware, options);

// Picasso
 Picasso.with(getContext())
                        .load(item.getPhotoUrl())
                        .placeholder(R.drawable.place_holder_big)
                        .resize(screenWidth, 0) //set max width
                        .into(viewHolder.imgFeed);

For UIL, I tried many ways in this issue but they don't work for me at all.

Update: seems I faced with memory cache issue like this question. But how can I fix this issue? Look at Facebook app, they did it very well. All images have different sizes with fit width, and very smooth scrolling without reloading images. How can they do that?

Renin answered 1/7, 2015 at 16:55 Comment(15)
Which version of Android you tested?Athabaska
It occurs when I download images in custom listview with images and text. Its because getView method is called for every item. You have to create your own vertical scroll list with the help of scrollviewSumer
@A.Anderson seems it occurred for all android versions. I tested on android 2.3, 4.4 and 5.0Renin
@KhushalChouhan so you mean that I shouldn't use a listview and redefine my own list widget? It looks weird because the official widget from Google can't handle it.Renin
Yes you have to create your own widget,definitely google can handle it but it needs strong knowledge of programming, Which i doesn't have, I rather created my own widget with scroll view and linear layout and its working faster then listview adapterSumer
"How can I prevent this happen?" -- have fewer or smaller (in RAM) images. "How can they do that?" -- they cheat and use system RAM outside of the Dalvik heap limit. Users may not be especially happy with you, as other apps that they have will get kicked out of RAM more quickly to satisfy your ravenous RAM hunger. And your process will be much shorter-lived once you move into the background, as Android tends to get rid of fat processes sooner than slim ones.Gautama
@Gautama thanks, I just try fresco lib, but it can't work in my app because I reach 65k methods limit, as my app has many libraries. The question is, if I don't cheat like this, I can't make it smoothly? And the Google+, twitter app are cheated as well? As I can see these has smooth scroll. I think there should have a way to achieve it without cheating memoryRenin
"if I don't cheat like this, I can't make it smoothly?" -- perhaps you can. However, your question does not ask how to "make it smoothly". Your question is asking about memory caching. Memory caching may be part of your problem, but there may be other aspects of "make it smoothly" that are causing you difficulty.Gautama
Beyond that, perhaps those other apps are downsampling their images smaller and having the GPU scale them up, to reduce per-image memory usage. Perhaps they have read them in as RGB_565 instead of ARGB_8888, to cut the per-image memory usage in half. Maybe they have a larger memory cache; the default ones for libraries like Picasso are usually set for something like 20% of your heap limit. Maybe the way you are testing those apps do not match your own tests, and if you do the same sort of quick-reverse scrolling, they will have similar issues.Gautama
Perhaps your cache is configured large enough, but you are using memory elsewhere in your app that has further constrained your cache size. Perhaps the problem is that you are suffering from Dalvik's heap fragmentation, and you only have a few big buffers that can hold those size of images, and so they have to be reclaimed more aggressively (and image caching libraries do not necessarily help with this). There are lots of possibilities here, far beyond what can be covered in a Stack Overflow answer.Gautama
On my conference videos page I have a presentation that I did last year at the Samsung Developer Conference on memory management. Perhaps something in there will give you some ideas.Gautama
@Gautama Thank you! Your advice should make sense. I'll check and try. If you can, please move all your comments into the answer, then I can accept it.Renin
Try to use .fit().centerCrop() options for Picasso. It looks like your images are too big to be cached properly, and this option will reduce them automatically to the visible area of the ImageView.Arzola
@Arzola well, I already used center crop scale for Picasso and UIL. But this is not my problem as I have to due with endless photo listRenin
I told you that because I saw in your example that you are using resize() with one of the values set to zero and this has no effect with Picasso (both values must be nonzero for the resize to occur).Arzola
H
4

If you're wondering how Facebook did it, they actually released their image loading library (https://github.com/facebook/fresco)

Is it possible you are actually calling notifyDataSetChanged on the underlying ListView at that time? Also are you using hasStableIds()?

For UIL you could try using a WeakMemoryCache (refer to https://github.com/nostra13/Android-Universal-Image-Loader/wiki/Useful-Info) as that'll theoretically allow you to make use of all available memory though it may cause a lot of extra GC calls.

For Picasso Taha's method looks like your best bet!

Hagans answered 8/7, 2015 at 18:51 Comment(0)
H
1

Maybe your memory cache size is small and Picasso tries to load images from disc cache. Please check here for deciding cache size. You can try to increase cache size of Picasso by:

Picasso p = new Picasso.Builder(context)
.memoryCache(new LruCache(cacheSize))
.build();

However in my opinion your app looks like having an endless feed. Which means your memory cache will be full at some time and you'll have to use disc cache. Retrieving data from the disc cache is slower compared to memory cache.

Humidistat answered 4/7, 2015 at 6:40 Comment(2)
I used both disk cache and memory cache with UIL, this issue still occurred (I haven't tried disk cache on Picasso yet, actually, I don't know how). But do you think disk cache will work?Renin
I think you need a bigger memory cache but in the end you'll end up with disc cache which will lead some latencies. Increasing the cache size will solve this? I'm not sure. Maybe the problem occurs because of not scrapping the list view items. I mean scrapping the views. Like in a recycler view.Humidistat

© 2022 - 2024 — McMap. All rights reserved.