Glide缓存

内存缓存、磁盘缓存、BitmapPool

Posted by candy1126xx on May 18, 2017

内存缓存

接口MemoryCache。默认实现LruResourceCache。

public class LruResourceCache <Key, Resource> {

    // 缓存的容器。Linkedxxx.accessOrder置为true,天生带Lru性质。
    private final LinkedHashMap<Key, Resource> cache = new LinkedHashMap<>(100, 0.75f, true);
    private int maxSize;
    private final int initialMaxSize;
    private int currentSize = 0;

    // 读取
    public Resource get(Key key) {
        return cache.get(key);
    }

    // 储存
    public Resource put(Key key, Resource item) {
        final int itemSize = item.getSize();
        // 如果储存对象大于最大容量,直接回收不储存
        if (itemSize >= maxSize) {
            onItemEvicted(key, item);
            return null;
        }

        // 储存,然后Lru清理空间
        final Resource result = cache.put(key, item);
        currentSize += getSize(item);
        trimToSize(maxSize);

        return result;
    }

    // 清理空间到size
    protected void trimToSize(int size) {
        Map.Entry<T, Y> last;
        while (currentSize > size) {
            last = cache.entrySet().iterator().next();
            final Resource toRemove = last.getValue();
            currentSize -= getSize(toRemove);
            final T key = last.getKey();
            cache.remove(key);
        }
    }
}

磁盘缓存

接口DiskCache。默认实现DiskLruCacheWrapper。

// 封装ReentrantLock和被重入次数
class WriteLock  {
    final Lock lock = new ReentrantLock();
    int interestedThreads;
}

// 多线程环境下的缓存,注意加锁的位置
class WriteLockPool {
    private static final int MAX_POOL_SIZE = 10;
    private final Queue<WriteLock> pool = new ArrayDeque<WriteLock>();

    WriteLock obtain() {
        WriteLock result;
        synchronized (pool) {
            result = pool.poll();
        }
        if (result == null) {
            result = new WriteLock();
        }
        return result;
    }

    void offer(WriteLock writeLock) {
        synchronized (pool) {
            if (pool.size() < MAX_POOL_SIZE) {
                pool.offer(writeLock);
            }
        }
    }
}

class DiskLruCache // 缓存操作的真正实现类。缓存容器也是LinkedHashMap。

class DiskCacheWriteLocker {
    private final Map<Key, WriteLock> locks = new HashMap<Key, WriteLock>();
    private final WriteLockPool writeLockPool = new WriteLockPool();

    // 申请锁
    void acquire(Key key) {
        WriteLock writeLock;
        synchronized (this) {
            writeLock = locks.get(key);
            if (writeLock == null) {
                writeLock = writeLockPool.obtain();
                locks.put(key, writeLock);
            }
            writeLock.interestedThreads++;
        }
        // 注意lock()是在synchronized{}外面的
        writeLock.lock.lock();
    }

    // 释放锁
    void release(Key key) {
        WriteLock writeLock;
        synchronized (this) {
            writeLock = locks.get(key);
            if (writeLock == null || writeLock.interestedThreads <= 0) {
                throw new IllegalArgumentException();
            }
            // 如果没有线程占用它,可以回收
            if (--writeLock.interestedThreads == 0) {
                WriteLock removed = locks.remove(key);
                if (!removed.equals(writeLock)) {
                    throw new IllegalStateException();
                }
                writeLockPool.offer(removed);
            }
        }
        // 注意unlock()是在synchronized{}外面的
        writeLock.lock.unlock();
    }
}

class DiskLruCacheWrapper implements DiskCache {

    private static final int APP_VERSION = 1;
    private static final int VALUE_COUNT = 1;
    
    // 单例
    private static DiskLruCacheWrapper wrapper = null;

    private final DiskCacheWriteLocker writeLocker = new DiskCacheWriteLocker();
    private final SafeKeyGenerator safeKeyGenerator;
    private final File directory;  // 缓存目录
    private final int maxSize;
    private DiskLruCache diskLruCache;

    public static synchronized DiskCache get(File directory, int maxSize) {
        if (wrapper == null) {
            wrapper = new DiskLruCacheWrapper(directory, maxSize);
        }
        return wrapper;
    }

    protected DiskLruCacheWrapper(File directory, int maxSize) {
        this.directory = directory;
        this.maxSize = maxSize;
        this.safeKeyGenerator = new SafeKeyGenerator();
    }

    private synchronized DiskLruCache getDiskCache() throws IOException {
        if (diskLruCache == null) {
            diskLruCache = DiskLruCache.open(directory, APP_VERSION, VALUE_COUNT, maxSize);
        }
        return diskLruCache;
    }

    private synchronized void resetDiskCache() {
        diskLruCache = null;
    }

    // 读取。
    @Override
    public File get(Key key) {
        String safeKey = safeKeyGenerator.getSafeKey(key);
        File result = null;
        try {
            final DiskLruCache.Value value = getDiskCache().get(safeKey);
            if (value != null) {
                result = value.getFile(0);
            }
        } catch (IOException e) {
        }
        return result;
    }
    
    // 储存。
    @Override
    public void put(Key key, Writer writer) {
        String safeKey = safeKeyGenerator.getSafeKey(key);
        writeLocker.acquire(key);
        try {
            DiskLruCache.Editor editor = getDiskCache().edit(safeKey);
            if (editor != null) {
                try {
                    File file = editor.getFile(0);
                    if (writer.write(file)) {
                        editor.commit();
                    }
                } finally {
                    editor.abortUnlessCommitted();
                }
            }
        } catch (IOException e) {

        } finally {
            writeLocker.release(key);
        }
    }
}