Universal Image Loader cache
Asked Answered
U

2

7

I'm trying to integrate Universal Image Loader into my Android App. It has a GridView and shows images acquired from internet. I implemented it using ArrayAdapter which loads images in getView() in a usual way.

It works well in terms of displaying picture correctly. But I found an unexpected behavior in loading images from memory cache.

  1. When activity is launched, UIL loads image from internet or disc cache if exists. (Of course, it is expected behavior.)
  2. Scrolling down GridView until first column go out from screen, and scroll back to the top. In this time, images at first column are loaded from disc cache, instead of memory cache.
  3. Then scrolling down and up again. In this time, images at first column are loaded from memory cache.

I expect images are loaded from memory cache at second time of displaying, which is step 2 in operation above. I don't know why disc cache is used in this case.

Here is my codes.

ImageLoaderConfiguration

ImageLoaderConfiguration mImageLoaderConfig =
        new ImageLoaderConfiguration.Builder(getApplicationContext())
                .defaultDisplayImageOptions(defaultOptions)
                .enableLogging()
                .build();

DisplayImageOptions

DisplayImageOptions defaultOptions =
        new DisplayImageOptions.Builder()
                .cacheInMemory()
                .cacheOnDisc()
                .showImageForEmptyUri(R.drawable.empty_photo)
                .showStubImage(R.drawable.empty_photo)
                .displayer(new FadeInBitmapDisplayer(500))
                .build();

getView() in ArrayAdapter

if (convertView == null) {
    convertView = (FrameLayout) LayoutInflater.from(getContext())
            .inflate(mLayoutId, null);
    convertView.setLayoutParams(mImageViewLayoutParams);
} else { // Otherwise re-use the converted view
    convertView.findViewById(R.id.videoIconInThumbnail).setVisibility(View.GONE);
}

// Check the height matches our calculated column width
if (convertView.getLayoutParams().height != mItemHeight) {
    convertView.setLayoutParams(mImageViewLayoutParams);
}

ImageView image = (ImageView) convertView.findViewById(R.id.photoThumbnail);
ImageLoader.getInstance().displayImage(thumbnailUrl, image,
        new SimpleImageLoadingListener() {

            @Override
            public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                Log.v(TAG, imageUri + " is loaded.");
            }
        });
return convertView;

layout XML for an element in GridView

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

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

    <ImageView
        android:id="@+id/videoIconInThumbnail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@drawable/ic_play"
        android:visibility="gone" >
    </ImageView>
</FrameLayout>

Version of UIL is 1.8.4. Tested Android version is 4.1.2.

Added log output of UIL when an image is loaded for three times with a operation described above.

// Fist time of displaying
I/ImageLoader( 7404): Start display image task [http://xxx/yyy.JPG_1080x1776]
I/ImageLoader( 7404): Load image from disc cache [http://xxx/yyy.JPG_1080x1776]
I/ImageLoader( 7404): Subsample original image (x192) to x192 (scale = 1) [http://xxx/yyy.JPG_1080x1776]
I/ImageLoader( 7404): Cache image in memory [http://xxx/yyy.JPG_1080x1776]
I/ImageLoader( 7404): Display image in ImageView [http://xxx/yyy.JPG_1080x1776]

// Second time of displaying
I/ImageLoader( 7404): ImageLoader is paused. Waiting...  [http://xxx/yyy.JPG_358x357]
I/ImageLoader( 7404): Start display image task [http://xxx/yyy.JPG_358x357]
I/ImageLoader( 7404): Load image from disc cache [http://xxx/yyy.JPG_358x357]
I/ImageLoader( 7404): Subsample original image (x192) to x192 (scale = 1) [http://xxx/yyy.JPG_358x357]
I/ImageLoader( 7404): Cache image in memory [http://xxx/yyy.JPG_358x357]
I/ImageLoader( 7404): Display image in ImageView [http://xxx/yyy.JPG_358x357]

// Third time of displaying
I/ImageLoader( 7404): Load image from memory cache [http://xxx/yyy.JPG_358x357]

Thank you.

Underestimate answered 8/5, 2013 at 14:51 Comment(0)
T
10

This is because of UIL's logic.

1) First time (ImageLoader.displayImage(...)) size of ImageView is unknown because it haven't drawn yet on screen. So UIL considers size of ImageView as full screen size, decodes image to Bitmap of this size (1080x1776, considering aspect ratio) and caches this Bitmap in memory.

2) Second time real size of drawn ImageView is known (which is smaller than full screen size) and UIL search cached Bitmap of appropriate size but cache contains only previous large Bitmap which is too large for our needs. So UIL decodes image again into smaller Bitmap and cache it in memory too.

3) Following displays uses already cached Bitmap of needed size.

So this is just a feature of UIL. I recommend you to use denyCacheImageMultipleSizesInMemory() in configuration to save memory.

Tatianatatianas answered 14/5, 2013 at 15:6 Comment(6)
thank you for your reply. I understand. There is no way to share same memory cache between images in different size to be loaded, right? If so, I'll consider other solutions. Thank you.Underestimate
I don't quite understand what do you mean by "share same memory cache between images in different size to be loaded".Tatianatatianas
I mean I would like UIL loads image from memory cache which has been cached previously even if the target sizes are different.Underestimate
No way for current version. Only if you change sources.Tatianatatianas
@NOSTRA is there any way cache maintain for one week only ?Untinged
Maybe LimitedAgeDiscCache. It requeries image from server after timeout (on 'get()' call).Tatianatatianas
A
0

NOSTRA's answer is right,to avoid this(load from disk cache when the second time request the image),you can let UIL know the ImageView's width/height before it deocode image, just add "android:maxWidth android:maxHeight" to the ImageView

Airdry answered 22/6, 2016 at 3:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.