Two level caching

This post builds off my post for disk caching. Sometimes you want a disk cache, to prevent unneeded network requests. Sometimes you want a memory cache, to put a cap on the amount of RAM you use. Sometimes you want both- you want a small fixed size working set in RAM, and a larger pool of objects saved to disk in case they’re needed. The solution is two level caching. The idea is that the memory cache is a subset of the disk cache, allowing you to page in from the disk cache to the memory cache as needed. Given you already have a disk cache (see previous post) the amount of extra code is pretty trivial. So I’ll skip the in depth discussion and just leave the solution here.

MemoryCache.java:

package com.gabesechan.android.reusable.cache;

import android.util.LruCache;


public class MemoryCache implements Cache{
    private CachePolicy mPolicy;

    private LruCache mCache;

    public MemoryCache(CachePolicy policy, int sizeMB) {
        mCache = new LruCache(sizeMB){
            @Override
            protected int sizeOf(KeyType key, ValueType value) {
                return (int)mPolicy.size(value);
            }
        };
        mPolicy = policy;
    }

    @Override
    public synchronized ValueType get(KeyType key) {
        return mCache.get(key);
    }

    @Override
    public synchronized boolean put(KeyType key, ValueType value) {
        mCache.put(key, value);
        return mCache.get(key) != null;
    }

    @Override
    public synchronized void remove(KeyType key) {
        mCache.remove(key);
    }

    @Override
    public synchronized void clear() {
        mCache.evictAll();
    }

}

TwoLevelCache.java:

package com.gabesechan.android.reusable.cache;

import java.io.File;

/**
 * A memory/disk cache.  Anything in the memory cache will also be in the disk cache.  The cache is
 * LRU
 */
public class TwoLevelCache implements Cache{
    private final CachePolicy mCachePolicy;
    private final MemoryCache mMemocyCache;
    private final DiskCache mDiskCache;


    public TwoLevelCache(CachePolicy policy, int memoryBytes, long diskBytes, long maxCacheTime, File cacheDir) {
        mCachePolicy = policy;

        if(diskBytes < memoryBytes){
            throw new IllegalArgumentException("Disk size must be bigger than memory size");
        }
        mMemocyCache = new MemoryCache<>(mCachePolicy, memoryBytes);
        mDiskCache = new DiskCache<>(mCachePolicy, diskBytes, maxCacheTime, cacheDir);
    }

    @Override
    public synchronized ValueType get(KeyType key) {
        ValueType result = mMemocyCache.get(key);
        if( result == null) {
            result = mDiskCache.get(key);
            if(result != null) {
                mMemocyCache.put(key, result);
            }
        }
        return result;
    }

    @Override
    public synchronized boolean put(KeyType key, ValueType value) {
        boolean result = mMemocyCache.put(key, value);
        return result || mDiskCache.put(key, value);
    }

    @Override
    public synchronized void remove(KeyType key) {
        mMemocyCache.remove(key);
        mDiskCache.remove(key);
    }

    public synchronized void clear() {
        mMemocyCache.clear();
        mDiskCache.clear();
    }
}

This Post Has Been Viewed 159 Times

Leave a Reply