Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Universal Image Loader cache

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.

like image 558
KSJ Avatar asked May 08 '13 14:05

KSJ


1 Answers

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.

like image 170
nostra13 Avatar answered Nov 06 '22 11:11

nostra13