【前言】
图片加载框架之内存缓存(一级缓存)设计(1) 中,我们采用HashMap 和 Reference 设计了图片内存缓存日常操作(增,删,查等)。
有了数据的操作之后,我接下来就开始设计大小的限制,因为我们每个app的内存都是有限制的,不可能让我们的缓存无限大。
【缓存大小设置的策略】
curCacheSize - 当前缓存大小(单位bit)
curBitmapSize - 要添加进来的bitmap的大小(单位bit)
sizeLimit - 我们将要限制的缓存的大小(单位bit)
(1)当我们往缓存里面添加一个bitmap的时候,如果curCacheSize + curBitmapSize 大于 sizeLimit,那么就不断删除掉缓存里面保存的bitmap,直到curCacheSize + curBitmapSize 小于 sizeLimit,我们才把要添加进来的bitmap加入缓存。但是,这样还是有可能出现oom风险的(当加入的bitmap过大的时候),这个我们后期再看下怎么处理。
(2)在(1)中,我们说到了“不断删除缓存里面保存的bitmap”,这里我们直接用抽象方法替代,因为删除的规则,后面子类可以拓展,方便我们设计删除策略(比如:先进先出,后进先出,LRU等)。
【代码】
import android.graphics.Bitmap;
import com.example.util.L;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* - 固定大小的缓存设计
* - 抽象方法 removeNext 可以拓展队列的规则(先进先出,后进先出等)
* - 抽象方法 getSize 根据bitmap,算出bit为单位的大小
* */
public abstract class LimitedMemoryCache extends BaseMemoryCache{
private static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16;//最大缓存,这里默认16 M
private static final int MAX_NORMAL_CACHE_SIZE = MAX_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024;
private final int sizeLimit;//缓存大小 单位bit
private final AtomicInteger curCacheSize;// 单位ibit
/**
* 这里保持有缓存的强引用,缓存对象add规则:加到最后一个
* 如果超过限制的大小,删除第一个缓存对象
* 但是超过的可以继续以at {@link #softMap} 存在 ( 父类 BaseMemoryCache里面的 Reference 集合)
* 数据结构采用链表型的集合 LinkedList,让插入和删除效率更高点
* 同时采用 synchronizedList 让本来不安全的 LinkedList 变得安全
*/
private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>());
/**@param limit Maximum size for cache (in bytes)
* @desc 设置缓存大小限制,但是不能操作最大限度,否则抛出异常
* */
public LimitedMemoryCache(int limit) {
sizeLimit = limit;
curCacheSize = new AtomicInteger();
if (sizeLimit > MAX_NORMAL_CACHE_SIZE) {
L.w("You set too large memory cache size (more than %1$d Mb)", MAX_NORMAL_CACHE_SIZE_IN_MB);
throw new RuntimeException("You set too large memory cache");
}
}
@Override
public boolean put(String key, Bitmap value) {
boolean putSuccessfully = false;
// 放进强引用集合里面
int valueSize = getSize(value);//取决于子类
int sizeLimit = getSizeLimit();
int curSize = curCacheSize.get();
if (valueSize < sizeLimit) {//
while (curSize + valueSize > sizeLimit) {// 当前大小 + 要put进来的大小 > 缓存大小limit,这时候删除
Bitmap removedValue = removeNext();//取决于子类(删除策略取决于子类)
if (hardCache.remove(removedValue)) {//删除强引用
curSize = curCacheSize.addAndGet(-getSize(removedValue));//更新当前的缓存大小
}
}
//添加
hardCache.add(value);
curCacheSize.addAndGet(valueSize);
putSuccessfully = true;
}
// Add value to soft cache (添加到父类的 Reference 集合)
super.put(key, value);
return putSuccessfully;
}
@Override
public Bitmap remove(String key) {
Bitmap value = super.get(key);//先在 父类 Reference 集合取出
if (value != null) {
if (hardCache.remove(value)) {//删除本类的强引用,更新当前缓存大小变量
curCacheSize.addAndGet(-getSize(value));
}
}
return super.remove(key);
}
@Override
public void clear() {
hardCache.clear();
curCacheSize.set(0);
super.clear();
}
protected int getSizeLimit() {
return sizeLimit;
}
protected abstract int getSize(Bitmap value);// 根据图片,得到大小
protected abstract Bitmap removeNext();//强引用 linklist 的删除规则,子类定义
}
【源码这里下载】
https://github.com/zgxzgxzg/openSource.git