Tuesday, July 19, 2016

LruCache Bitmaps


A cache that holds strong references to a limited number of values. Each time a value is accessed, it is moved to the head of a queue. When a value is added to a full cache, the value at the end of that queue is evicted and may become eligible for garbage collection.

Loading a single bitmap into your user interface (UI) is straightforward, however things get more complicated if you need to load a larger set of images at once. In many cases (such as with components like ListView, GridView or ViewPager), the total number of images on-screen combined with images that might soon scroll onto the screen are essentially unlimited.

Memory usage is kept down with components like this by recycling the child views as they move off-screen. The garbage collector also frees up your loaded bitmaps, assuming you don't keep any long lived references. This is all good and well, but in order to keep a fluid and fast-loading UI you want to avoid continually processing these images each time they come back on-screen. A memory and disk cache can often help here, allowing components to quickly reload processed images.

A memory cache offers fast access to bitmaps at the cost of taking up valuable application memory. The LruCache class (also available in the Support Library for use back to API Level 4) is particularly well suited to the task of caching bitmaps, keeping recently referenced objects in a strong referenced LinkedHashMap and evicting the least recently used member before the cache exceeds its designated size.

It is a cache that holds strong references to a limited number of values. Each time a value is accessed, it is moved to the head of a queue. When a value is added to a full cache, the value at the end of that queue is evicted and may become eligible for garbage collection.

A cache that is too small causes additional overhead with no benefit, a cache that is too large can once again cause java.lang.OutOfMemory exceptions and leave the rest of your app little memory to work with.

Here’s an example of setting up a LruCache for bitmaps:

private LruCache mLruCache;
public CustomListAdapter(Context context, ArrayList listData) {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 4;
        mLruCache = new LruCache(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                // The cache size will be measured in kilobytes
                return bitmap.getByteCount() / 1024;
            }
        };
        this.listData = listData;
        layoutInflater = LayoutInflater.from(context);
    }
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemCache(key) == null) {
            mLruCache.put(key, bitmap);
        }
    }
public Bitmap getBitmapFromMemCache(String key) {
return mLruCache.get(key);
}

When loading a bitmap into an ImageView, the LruCache is checked first. If an entry is found, it is used immediately and update the ImageView, otherwise a background thread is spawned to process the image:

Bitmap thumbnailImage = getBitmapFromMemCache(newsItem.getUrl());
    if (thumbnailImage == null) {
    new ImageLoadingTask(holder.imageView).execute(newsItem.getUrl());
    } else {
holder.imageView.setImageBitmap(thumbnailImage);
        Log.d("FileSize", "Cached stored");
    }
Suppose we have a list of images in application. When user scrolls down, application has to load next images. If we will load the images directly from source it will take more time. And what if user scrolls up, then we have to fetch those recently used bitmaps again causing a wastage of resources. This is not a suitable approach if we have a lot of bitmaps in application. In such case LruCache would be helpful. It will fetch the images, put them into cache and will only remove the least recently used bitmap which means the bitmap not used for the longest time.

Here is the full source code download here

No comments:

Post a Comment