【概要】
数据结构存储 - LinkedHashMap;默认先进先出规则。
缓存大小采用app内存的1/8,单位MB
这里的话,基本没什么难度,都是一些日常操作,直接上代码。
【LruMemoryCache】
public class LruMemoryCache implements MemoryCache{
private final LinkedHashMap<String, Bitmap> map;// 默认 - (先进先出)
private final int maxSize;//单位 - bytes; 最大容量限制
private int curSize;//单位 - bytes; 当前缓存大小
/** @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */
public LruMemoryCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);// 加载因子 - http://my.oschina.net/weiweiblog/blog/612812
}
/***
* 放到队列的头
* */
@Override
public final boolean put(String key, Bitmap value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
synchronized (this) {
curSize += sizeOf(value);
Bitmap previous = map.put(key, value);//先put,如果一个bitmap大到离谱才oom吧,毕竟app内存的1/8才用来缓存
if (previous != null) {
curSize -= sizeOf(previous);
}
}
//
trimToSize(maxSize);
return true;
}
/**
* Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head
* of the queue. This returns null if a Bitmap is not cached.
*/
@Override
public final Bitmap get(String key) {
if (key == null) {
throw new NullPointerException("key == null");
}
synchronized (this) {
return map.get(key);
}
}
@Override
public Bitmap remove(String key) {
if (key == null) {
throw new NullPointerException("key == null");
}
synchronized (this) {
Bitmap previous = map.remove(key);
if (previous != null) {
curSize -= sizeOf(previous);
}
return previous;
}
}
@Override
public Collection<String> keys() {
synchronized (this) {
return new HashSet<String>(map.keySet());
}
}
@Override
public void clear() {
trimToSize(-1); // -1 will evict 0-sized elements
}
/**
* @desc 计算一个 Bitmap 的大小
* @return 单位为bytes的大小
*/
private int sizeOf(Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
/**
* Remove the eldest entries until the total of remaining entries is at or below the requested curSize.
*
* @param maxSize the maximum curSize of the cache before returning. May be -1 to evict even 0-sized elements.
*/
private void trimToSize(int maxSize) {
while (true) {
String key;
Bitmap value;
synchronized (this) {
if (curSize < 0 || (map.isEmpty() && curSize != 0)) {
throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");
}
if (curSize <= maxSize || map.isEmpty()) {
break;
}
Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();
// [entrySet 学习url] - http://blog.csdn.net/huxin1/article/details/6171023
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
curSize -= sizeOf(value);
}
}
}
@Override
public synchronized final String toString() {
return String.format("LruCache[maxSize = %d bytes]", maxSize);
}
}
【配置工厂 - ConfigurationFactory】
public class ConfigurationFactory {
private static final int CONFIG_MEMORY_DIV = 8;
private static final int MB = 1024 * 1024;
/**
* Creates default implementation of {@link MemoryCache} - {@link LruMemoryCache}<br />
*/
public static MemoryCache createMemoryCache(Context context, int memoryCacheSize) {
if(memoryCacheSize < 0 )memoryCacheSize = 0;
if (memoryCacheSize == 0) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();//MB
if (hasHoneycomb() && isLargeHeap(context)) {
memoryClass = getLargeMemoryClass(am);
}
memoryCacheSize = MB * memoryClass / CONFIG_MEMORY_DIV;//默认app内存的1/8
}
return new LruMemoryCache(memoryCacheSize);
}
private static boolean hasHoneycomb() {// Android 3.1
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
}
/*
* application的标记位,是否需要高耗内存
* 学习链接 - http://blog.csdn.net/zhangli_/article/details/51735395
* */
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private static boolean isLargeHeap(Context context) {
// flag & MB
return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_LARGE_HEAP) != 0;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private static int getLargeMemoryClass(ActivityManager am) {
return am.getLargeMemoryClass();
}
}