Volley and bitmap caching
Asked Answered
U

6

6

I'm trying to display a listview with a lot of (remote) images. I'm trying to use volley for the task.

Volley somewhat works, but not good enough. In ImageLoader.get volley has the following piece of code:

    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;
    }

However, getCacheKey produces a key like this:

/**
 * 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();
}

i.e. It appends some "metadata" like width and height to the key.

This key never produces a hit and if the image is not in the L1 cache it is fetched online. When the image is fetched online it is saved in the disk-cache but Volley saves it with the URL (and only the URL) as key.

Is this expected behaviour? Am I missing something?

Unconcerned answered 15/7, 2013 at 7:6 Comment(3)
it could depend on the headers from your responseRichmal
have you figure it out why volley don't produce a hit?Lillia
You can use droidQuery to complete async restful requests (Ajax), and control cacheing easier (whether or not to, and how long to keep a cached object).Dedededen
T
9

The reason you're not getting any hits is because the default behavior in Volley for disk caching is dependent on the HTTP headers of the element you're requesting (in your case, an image).

The way Volley works is:

  1. ImageLoader checks the L1 cache for image (memory cache provided by you to the ImageLoader in its constructor). If available return image.
  2. Request processed by RequestQueue. It checks the L2 (disk cache) for the image.
  3. If found in the disk cache, check the image expiry time. If not expired, return.
  4. Download image and return it.
  5. Save image in caches.

If you want the default settings to work, the images must have a Cache-Control header like max-age=??? where the question marks indicate enough seconds from the time it was downloaded.

If you want to change the default behavior, I'm not sure, but I think you have to edit the code a bit.

Look at the CacheDispatcher class in the Volley source.

Tokenism answered 31/7, 2013 at 13:32 Comment(0)
D
2

I tracked down this issue in my own app today. I was setting a max cache size in KB in the constructor, but reporting a size in bytes in sizeOf(), so nothing was ever cached.

This answer set me straight.

Dauphin answered 2/10, 2013 at 22:7 Comment(0)
C
1

Can you post your class that implements ImageCache.

I've just been looking at this myself and realised in my code I wasn't adding the bitmap to the memory cache when it was loading it from the disk, so it would always reload it from the disk each time.

This is a simple example of what I mean and where I was going wrong

@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;
    }
Charlean answered 23/7, 2013 at 14:43 Comment(0)
A
1

Probably you are using NetworkImageView to load your images. You can use a ImageView and ImageLoader to do the same thing. Using ImageLoader the metadata in the key is like "#W0#H0" for any image size.

ImageLoader imageLoader = getImageLoader();
imageLoader.get(url, ImageLoader.getImageListener(imageView, defaultDrawable, errorDrawable));
Amphitropous answered 25/8, 2015 at 20:25 Comment(0)
R
0

Volley wont cache anything, if cache control is not set in the response header.

Check the HttpHeaderParser class implementation in Volley.

Caching can be based on max-age or E-tag. Check your response header and identify anything set there. It will look something like this.

Cache-Control → public, max-age=300

Cache Header info

Retrograde answered 2/4, 2015 at 14:7 Comment(0)
H
-1

This is the exact way you want it to work.

  1. Hit the url and get the image when its not available.
  2. Load the image from the cache if available.
Hormonal answered 15/7, 2013 at 7:16 Comment(3)
This does not make sense. First of all you want to load the image from the cache before you hit the url. Secondly this does not answer my question about how volley workksUnconcerned
I understood your question as if it worked the way you mentioned in the above comment.Hormonal
I don't understand what you are saying. I asked "why do the internal volley cache never produce a hit"Unconcerned

© 2022 - 2024 — McMap. All rights reserved.