从网上找到的,自己整理了下:
public class MemoryCache { private static final String TAG = "MemoryCache"; /** * 放入缓存时是个同步操作 * LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最近使用次数由少到多排列,即LRU * 这样的好处是如果要将缓存中的元素替换,则先遍历出最近最少使用的元素来替换以提高效率 */ private Map<String, Bitmap> mCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(10, 1.5f, true)); /** * 缓存中图片所占用的字节,初始0,将通过此变量严格控制缓存所占用的堆内存 */ private long mSize = 0; /** * 缓存只能占用的最大堆内存 */ private long mLimit = 1000000; public MemoryCache() { setLimit(Runtime.getRuntime().maxMemory() / 10); } /** * 设置内存使用上限 * @param limit */ public void setLimit(long limit) { mLimit = limit; Log.i(TAG, "MemoryCache will use up to " + (mLimit / 1024. / 1024.) + "MB"); } /** * 获取内存中缓存的图片资源 * * @param key * @return */ public Bitmap get(String key) { try { if (! mCache.containsKey(key)) return null; return mCache.get(key); } catch (NullPointerException ex) { return null; } } /** * 将图片资源缓存到内存 * * @param key * @param bitmap */ public void put(String key, Bitmap bitmap) { try { if (mCache.containsKey(key)) mSize -= getSizeInBytes(mCache.get(key)); mCache.put(key, bitmap); // 累计当前缓存已使用的内存大小 mSize += getSizeInBytes(bitmap); checkSize(); } catch (Throwable th) { th.printStackTrace(); } } /** * 检测图片缓存的内存占用 */ private void checkSize() { Log.i(TAG, "cache size=" + mSize + " length=" + mCache.size()); if (mSize > mLimit) { // 先遍历最近最少使用的元素 Iterator<Map.Entry<String, Bitmap>> iterator = mCache.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Bitmap> entry = iterator.next(); mSize -= getSizeInBytes(entry.getValue()); iterator.remove(); if (mSize <= mLimit) break; } Log.i(TAG, "Clean cache. New size " + mCache.size()); } } /** * 清空内存缓存 */ public void clear() { mCache.clear(); } /** * 图片占用的内存 * * @param bitmap * @return */ long getSizeInBytes(Bitmap bitmap) { if (bitmap == null) return 0; return bitmap.getRowBytes() * bitmap.getHeight(); } }
首先限制内存图片缓冲的堆内存大小,每次有图片往缓存里加时判断是否超过限制大小,超过的话就从中取出最少使用的图片并将其移除,当然这里如果不采用这种方式,换做软引用也是可行的,二者目的皆是最大程度的利用已存在于内存中的图片缓存,避免重复制造垃圾增加GC负担,OOM溢出往往皆因内存瞬时大量增加而垃圾回收不及时造成的。只不过二者区别在于LinkedHashMap里的图片缓存在没有移除出去之前是不会被GC回收的,而SoftReference里的图片缓存在没有其他引用保存时随时都会被GC回收。所以在使用LinkedHashMap这种LRU算法缓存更有利于图片的有效命中,当然二者配合使用的话效果更佳,即从LinkedHashMap里移除出的缓存放到SoftReference里,这就是内存的二级缓存,有兴趣的童鞋不凡一试。