【问题标题】:Universal Image Loader cache通用图像加载器缓存
【发布时间】:2013-05-02 20:50:39
【问题描述】:

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

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

  1. 启动活动时,UIL 从 Internet 或磁盘缓存(如果存在)加载图像。 (当然,这是预期行为。)
  2. 向下滚动 GridView 直到第一列从屏幕上移出,然后滚动回顶部。 此时,第一列的图像是从磁盘缓存而不是内存缓存加载的。
  3. 然后再次向下和向上滚动。 此时,第一列的图像从内存缓存中加载。

我希望图像在第二次显示时从内存缓存中加载,这是上面操作中的第 2 步。 我不知道为什么在这种情况下使用磁盘缓存。

这是我的代码。

ImageLoader 配置

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

显示图像选项

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]

谢谢。

【问题讨论】:

    标签: universal-image-loader


    【解决方案1】:

    这是因为 UIL 的逻辑。

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

    2) 第二次绘制的 ImageView 的实际大小已知(小于全屏大小)并且 UIL 搜索缓存的适当大小的位图,但缓存仅包含以前的大位图,这对于我们的需要来说太大了。所以 UIL 将图像再次解码成更小的 Bitmap 并缓存在内存中。

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

    所以这只是 UIL 的一个特性。我建议你在配置中使用denyCacheImageMultipleSizesInMemory()以节省内存。

    【讨论】:

    • 感谢您的回复。我明白。没有办法在要加载的不同大小的图像之间共享相同的内存缓存,对吧?如果是这样,我会考虑其他解决方案。谢谢。
    • 我不太明白“要加载的不同大小的图像之间共享相同的内存缓存”是什么意思。
    • 我的意思是我希望 UIL 从内存缓存中加载图像,即使目标大小不同。
    • 当前版本不行。仅当您更改来源时。
    • @NOSTRA 有没有办法只维持一周的缓存?
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2015-06-20
      • 2015-04-02
      • 2014-01-14
      • 2016-02-29
      • 2014-10-14
      • 2013-12-17
      • 2014-01-19
      • 2023-03-18
      • 2016-12-15
      相关资源
      最近更新 更多