35

I am having trouble implementing Image cache using the new Volley library. In the presentation, code look like this

mRequestQueue = Volley.newRequestQueue(context);
mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache());

The BitmapLruCache is obviously not included in the toolkit. Any idea how to implement it or point me to some resources?

http://www.youtube.com/watch?v=yhv8l9F44qo @14:38

Thanks!

urSus
  • 12,492
  • 12
  • 69
  • 89

5 Answers5

50
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

public class BitmapLruCache extends LruCache<String, Bitmap> implements ImageCache {
    public static int getDefaultLruCacheSize() {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;

        return cacheSize;
    }

    public BitmapLruCache() {
        this(getDefaultLruCacheSize());
    }

    public BitmapLruCache(int sizeInKiloBytes) {
        super(sizeInKiloBytes);
    }

    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight() / 1024;
    }

    @Override
    public Bitmap getBitmap(String url) {
        return get(url);
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        put(url, bitmap);
    }
}
likeitlikeit
  • 5,563
  • 5
  • 42
  • 56
Vladimir Mironov
  • 30,514
  • 3
  • 65
  • 62
  • thanks a lot, by the way, how do you determine the proper size of your cache? he talks about that its a function of screen size, seems logical, but how do I make it more exact? – urSus May 25 '13 at 19:52
  • @Vlasto Benny Lava, I'm not sure, but something like `N * screen_width * screen_height` with `N ~ 10` seems logical for me. – Vladimir Mironov May 26 '13 at 10:38
  • because now what happens is works nicely, but image loads again if it goes off screen and comes back, so I presume it was kicked out of memory cache right? Any idea what that could be? – urSus May 26 '13 at 14:45
  • @Vlasto Benny Lava, cache size could be a problem. How is it calculated right now? – Vladimir Mironov May 26 '13 at 15:56
  • now its exactly as in your answer, I am using Samsung Galaxy S3 som thats weird, cache size should be able to take atleast 3 screens right? – urSus May 26 '13 at 20:50
  • @Vlasto Benny Lava, the implementation above works well on my nexus 4. Try logging values returned from `getDefaultLruCacheSize` and `sizeOf` and see if everything is ok or not. – Vladimir Mironov May 27 '13 at 03:22
  • its works now, I forgot the / 1024 as I was looking both at yours and Ficus' example. thanks – urSus May 27 '13 at 15:36
  • 2
    @njzk2 to prevent `int` overflow. `Runtime.maxMemory()` returns `long` and casting to `int` can cuase an overflow. The division is just to minimize the possibility. – Vladimir Mironov Jun 04 '13 at 15:51
  • Note that if you're supporting < API 12, you should make sure you use the support v4 library's version of LruCache rather than the standard version, or it'll crash on Gingerbread devices. – DesignatedNerd Jun 14 '13 at 16:49
7

Ficus provides this sample code for the Bitmap LRU:

https://gist.github.com/ficusk/5614325

Keith
  • 2,958
  • 4
  • 26
  • 29
5

Here is an example of using a Disk based LRU cache with Volley. It is based on using a version of AOSP's DiskLruCache maintained by Jake Wharton. http://blogs.captechconsulting.com/blog/raymond-robinson/google-io-2013-volley-image-cache-tutorial

Edit: I have updated the project to include an in-memory LRU cache as the default implementation as this is the recommended method. Volley implicitly handles disk based cache in its own L2 cache. The image cache is just the L1 cache. I updated the original post and added some more detail here: http://www.thekeyconsultant.com/2013/06/update-volley-image-cache.html.

yincrash
  • 6,394
  • 1
  • 39
  • 41
rdrobinson3
  • 360
  • 1
  • 4
  • 1
    In your library, you seem to be using url.hashCode() to generate the key required by the disk cache. Is that really safe? hashCodes aren't unique, so won't you risk getting false cache hits for URL's that randomly resolves to the same hash code? I've seen others use MD5 to reduce the risk of collisions, some even providing their own MD5 implementation to avoid Androids non-threadsafe MessageDigest class. Any suggestions regarding this (potential) issue? – Nicolai Buch-Andersen Jun 03 '13 at 21:44
  • 1
    You are correct, this was just put in place for the demo and works the majority of the time. I am testing the speed of UUID.fromString() as a viable alternative. – rdrobinson3 Jun 06 '13 at 17:10
1

What I advise is using a Singleton Bitmap Cache so this cache is going to be available during all the life of your app.

public class BitmapCache implements ImageCache {
    private LruCache<String, Bitmap> mMemoryCache;

    private static BitmapCache mInstance;

    private BitmapCache(Context ctx) {
        final int memClass = ((ActivityManager) ctx
                .getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
        // Use 1/16th of the available memory for this memory cache.
        final int cacheSize = 1024 * 1024 * memClass / 16;
        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight();
            }
        };
    }

    public static BitmapCache getInstance(Context ctx) {
        if (mInstance == null) {
            mInstance = new BitmapCache(ctx);
        }
        return mInstance;
    }

    @Override
    public Bitmap getBitmap(String url) {
        return mMemoryCache.get(url);
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        mMemoryCache.put(url, bitmap);
    }
}
Vladimir Mironov
  • 30,514
  • 3
  • 65
  • 62
Manolo Garcia
  • 3,785
  • 2
  • 19
  • 19
0

this is comes in new API to handle the OOM

public class BitmapMemCache extends LruCache<string, Bitmap> implements ImageCache {

    public BitmapMemCache() {
        this((int) (Runtime.getRuntime().maxMemory() / 1024) / 8);
    }

    public BitmapMemCache(int sizeInKiloBytes) {
        super(sizeInKiloBytes);
    }

    @Override
    protected int sizeOf(String key, Bitmap bitmap) {
        int size = bitmap.getByteCount() / 1024;
        return size;
    }

    public boolean contains(String key) {
        return get(key) != null;
    }

    public Bitmap getBitmap(String key) {
        Bitmap bitmap = get(key);
        return bitmap;
    }

    public void putBitmap(String url, Bitmap bitmap) {
        put(url, bitmap);
    }
}
Sunil Kumar
  • 7,086
  • 4
  • 32
  • 50