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?

Community
  • 1
  • 1
ductran
  • 10,043
  • 19
  • 82
  • 165
  • Which version of Android you tested? – Anderson K Jul 04 '15 at 03:32
  • 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 scrollview – Khushal Chouhan Jul 04 '15 at 05:25
  • @A.Anderson seems it occurred for all android versions. I tested on android 2.3, 4.4 and 5.0 – ductran Jul 04 '15 at 06:20
  • @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. – ductran Jul 04 '15 at 06:23
  • 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 adapter – Khushal Chouhan Jul 04 '15 at 07:08
  • "How can I prevent this happen?" -- have fewer or smaller (in RAM) images. "How can they do that?" -- [they cheat](https://github.com/facebook/fresco) 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. – CommonsWare Jul 04 '15 at 22:31
  • @CommonsWare 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 memory – ductran Jul 06 '15 at 02:43
  • "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. – CommonsWare Jul 06 '15 at 11:47
  • 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. – CommonsWare Jul 06 '15 at 11:58
  • 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. – CommonsWare Jul 06 '15 at 12:00
  • On my [conference videos page](https://commonsware.com/videos) 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. – CommonsWare Jul 06 '15 at 12:01
  • @CommonsWare 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. – ductran Jul 08 '15 at 04:20
  • 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. – BladeCoder Jul 09 '15 at 11:50
  • @BladeCoder 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 list – ductran Jul 09 '15 at 13:28
  • 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). – BladeCoder Jul 09 '15 at 14:51

2 Answers2

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!

Nyx
  • 2,233
  • 1
  • 12
  • 25
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.

Taha
  • 531
  • 4
  • 21
  • 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? – ductran Jul 04 '15 at 15:14
  • 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. – Taha Jul 05 '15 at 23:21