通用图像加载器缓存

时间:2013-05-08 14:51:29

标签: universal-image-loader

我正在尝试将Universal Image Loader集成到我的Android App中。 它有一个GridView,显示从互联网上获取的图像。 我使用ArrayAdapter实现它,它以通常的方式在getView()中加载图像。

在正确显示图片方面效果很好。 但是我在从内存缓存加载图像时发现了一个意外的行为。

  1. 启动活动时,UIL会加载来自互联网或光盘缓存的图像(如果存在)。 (当然,这是预期的行为。)
  2. 向下滚动GridView,直到第一列从屏幕中退出,然后滚动回到顶部。 在这段时间,第一列的图像是从光盘缓存加载而不是内存缓存。
  3. 然后再向上滚动。 在这段时间,第一列的图像从内存缓存加载。
  4. 我希望在第二次显示时从内存缓存加载图像,这是上面的操作中的第2步。 我不知道为什么在这种情况下会使用光盘缓存。

    这是我的代码。

    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();
    

    ArrayAdapter中的getView()

    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;
    

    GridView中元素的布局XML

    <?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>
    

    UIL的版本是1.8.4。 经测试的Android版本为4.1.2。

    使用上述操作将图像加载三次时,添加了UIL的日志输出。

    // 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]
    

    谢谢。

2 个答案:

答案 0 :(得分:10)

这是因为UIL的逻辑。

1)第一次(ImageLoader.displayImage(...))ImageView的大小未知,因为它尚未在屏幕上绘制。因此,UIL将ImageView的大小视为全屏大小,将图像解码为此大小的位图(1080x1776,考虑宽高比)并将此位图缓存在内存中。

2)第二次绘制的ImageView的实际大小是已知的(小于全屏大小),UIL搜索缓存了适当大小的Bitmap,但缓存只包含以前的大型Bitmap,这对我们的需求来说太大了。因此,UIL将图像再次解码为较小的Bitmap,并将其缓存在内存中。

3)以下显示使用已缓存的所需大小的位图。

所以这只是UIL的一个功能。我建议您在配置中使用denyCacheImageMultipleSizesInMemory()来节省内存。

答案 1 :(得分:0)

NOSTRA的答案是对的,为了避免这种情况(第二次请求图像时从磁盘缓存加载),你可以让UIL在它解码图像之前知道ImageView的宽度/高度,只需添加“android:maxWidth android:maxHeight”到ImageView