Volley和位图缓存技术

6

我想显示一个带有许多(远程)图片的列表视图。我试图使用Volley来完成这个任务。

Volley有些有效,但效果不够好。在ImageLoader.get中,Volley有以下代码:

    final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);

    // Try to look up the request in the cache of remote images.
    Bitmap cachedBitmap = mCache.getBitmap(cacheKey);
    if (cachedBitmap != null) {
        // Return the cached bitmap.
        ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);
        imageListener.onResponse(container, true);
        return container;
    }

然而,getCacheKey 生成的键如下:
/**
 * Creates a cache key for use with the L1 cache.
 * @param url The URL of the request.
 * @param maxWidth The max-width of the output.
 * @param maxHeight The max-height of the output.
 */
private static String getCacheKey(String url, int maxWidth, int maxHeight) {
    return new StringBuilder(url.length() + 12).append("#W").append(maxWidth)
            .append("#H").append(maxHeight).append(url).toString();
}

即它会将一些像宽度和高度之类的“元数据”附加到键上。

这个键永远不会产生命中,如果图像不在L1缓存中,它将在线获取。当图像在线获取时,它将保存在磁盘缓存中,但Volley仅使用URL(而不是其他内容)作为键来保存它。

这是预期的行为吗?我有什么遗漏的吗?


它可能取决于您响应中的标头。 - njzk2
1
你弄清楚为什么Volley没有产生命中的结果了吗? - chr.solr
你可以使用droidQuery来完成异步RESTful请求(Ajax),并更轻松地控制缓存(无论是否以及保留缓存对象的时间)。 - Phil
6个回答

9
你没有得到任何结果的原因是,Volley中关于磁盘缓存的默认行为取决于你请求的元素(在你的情况下是图片)的HTTP头信息。
Volley的工作方式如下:
1. ImageLoader检查L1缓存是否有图片(由你提供给ImageLoader的内存缓存)。如果有,返回图片。
2. 请求被RequestQueue处理。它检查L2(磁盘缓存)中是否有该图片。
3. 如果在磁盘缓存中找到了该图片,则检查图片的过期时间。如果没有过期,则返回。
4. 下载图片并返回。
5. 将图片保存在缓存中。
如果你想使用默认设置,那么图片必须有一个Cache-Control头,例如max-age=???,其中问号表示从下载时间开始的足够秒数。
如果你想改变默认行为,我不确定,但我认为你需要稍微编辑一下代码。
请查看Volley源码中的CacheDispatcher类。

2
我今天在自己的应用程序中追踪了这个问题。我在构造函数中设置了最大缓存大小(以KB为单位),但在sizeOf()中报告的是以字节为单位的大小,因此没有任何内容被缓存。 这个答案纠正了我的错误。

1
您可能正在使用NetworkImageView加载图像。您可以使用ImageView和ImageLoader来完成相同的操作。使用ImageLoader,密钥中的元数据对于任何图像大小都是“#W0#H0”。
ImageLoader imageLoader = getImageLoader();
imageLoader.get(url, ImageLoader.getImageListener(imageView, defaultDrawable, errorDrawable));

1

你能发布实现ImageCache的类吗?

我刚刚也在研究这个问题,意识到在我的代码中,当它从磁盘加载位图时,我没有将其添加到内存缓存中,因此每次都会重新从磁盘加载。

这是我指的问题和错误示例。

@Override
    public Bitmap getBitmap(String cachKey) {

        Bitmap b = null;

            //check the memory first
            b = memoryCache.get(cacheKey);
            if(b == null){
                //memory cache was null, check file cache           
                b = diskLruImageCache.getBitmap(cacheKey);

                // this is where it needs to be added to your memory cache
                if(b != null){
                    memoryCache.put(url, b);
                }
            }



        return b;
    }

0

如果响应头中未设置缓存控制,Volley 将不会缓存任何内容。

请检查 Volley 中 HttpHeaderParser 类的实现。

缓存可以基于最大年龄或 E-tag。请检查您的响应头并确定其中是否设置了任何内容。它将类似于以下内容。

Cache-Control → public, max-age=300

缓存头信息


-1

这就是你想要的工作方式。

  1. 访问 URL 并在图像不可用时获取它。
  2. 如果缓存中有可用的图像,则加载缓存中的图像。

这没有意义。首先,您希望在访问URL之前从缓存中加载图像。其次,这并没有回答我的问题,即Volley如何工作。 - Markus
我理解你的问题是指它按照你在上面评论中提到的方式运作。 - Naresh
我不明白你在说什么。我问了“为什么内部Volley缓存从未命中”。 - Markus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接