bitmap的缓存
在build Glide 时 会初始化根据版本不同会选择一个bitmap的缓存策略 LruBitmapPool
Glide createGlide() {
if (sourceService == null) {
final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
sourceService = new FifoPriorityThreadPoolExecutor(cores);
}
if (diskCacheService == null) {
diskCacheService = new FifoPriorityThreadPoolExecutor(1);
}
MemorySizeCalculator calculator = new MemorySizeCalculator(context);
if (bitmapPool == null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
int size = calculator.getBitmapPoolSize();
bitmapPool = new LruBitmapPool(size);//**注意这里** 如果大于11 就会创建一个默认的Lru算法的bitmap缓存池
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
if (memoryCache == null) {
memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
}
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
if (engine == null) {
engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
}
if (decodeFormat == null) {
decodeFormat = DecodeFormat.DEFAULT;
}
return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
}
LruBitmapPool: 负责控制缓存
LruPoolStrategy : 他的实现类 , 负责真正的缓存bitmap
默认每次在put的时候 , 都会累计内存用量 , 判断如果当前使用量大于允许的最大内存就会移除链表的表尾, 最新的默认会移动到表头;这就是最近最少使用算法;
//可以设置缓存的大小maxSize , 有2个默认的策略实现,第一个真正缓存功能的实现类 , LruBitmapPool 只是转发类 , 真正实现缓存是他 LruPoolStrategy
第二个允许bitmap的类型
/**
* Constructor for LruBitmapPool.
*
* @param maxSize The initial maximum size of the pool in bytes.
*/
public LruBitmapPool(int maxSize) {
this(maxSize, getDefaultStrategy(), getDefaultAllowedConfigs());
}
// 使用 SizeConfigStrategy 策略
private static LruPoolStrategy getDefaultStrategy() {
final LruPoolStrategy strategy;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
strategy = new SizeConfigStrategy();
} else {
strategy = new AttributeStrategy();
}
return strategy;
}
//Bitmap.Config 是个枚举, 把默认bitmap类型都放到容器里
private static Set<Bitmap.Config> getDefaultAllowedConfigs() {
Set<Bitmap.Config> configs = new HashSet<Bitmap.Config>();
configs.addAll(Arrays.asList(Bitmap.Config.values()));
if (Build.VERSION.SDK_INT >= 19) {
configs.add(null);
}
return Collections.unmodifiableSet(configs);
}
public static enum Config {
ALPHA_8,
ARGB_4444,
ARGB_8888,
HARDWARE,
RGBA_F16,
RGB_565;
private Config() {
}
}
来分析下 大于19版本 SizeConfigStrategy 他的实现思路;
以put 第二行 , 以bitmap的占用大小 和 他的bitmap像素类型 ,让一个key对象来包裹 , 封装成GroupedLinkedMap的key了, 依靠 自定义的 linkedHashMap , 把匹配的取出来并设置成表头;
GroupedLinkedMap 类:
// Make the entry the most recently used item.
private void makeHead(LinkedEntry<K, V> entry) {
removeEntry(entry);
entry.prev = head;
entry.next = head.next;
updateEntry(entry);
}
private final KeyPool keyPool = new KeyPool();
private final GroupedLinkedMap<Key, Bitmap> groupedMap = new GroupedLinkedMap<Key, Bitmap>();
@Override
public void put(Bitmap bitmap) {
int size = Util.getBitmapByteSize(bitmap);//bitmap 占用内存大小
Key key = keyPool.get(size, bitmap.getConfig());
groupedMap.put(key, bitmap);
NavigableMap<Integer, Integer> sizes = getSizesForConfig(bitmap.getConfig());
Integer current = sizes.get(key.size);
sizes.put(key.size, current == null ? 1 : current + 1);
}
//keyPool 的 get 方法 , 默认先去队列里找 , 如果不为空就取出来 ,然后从新赋值新的属性 , 以复用对象 , 真是一点内存(多创建一个对象)都不浪费;
public Key get(int size, Bitmap.Config config) {
Key result = get();
result.init(size, config);
return result;
}
//队列为空才创建新的
protected T get() {
T result = keyPool.poll();
if (result == null) {
result = create();
}
return result;
}
来看取bitmap , 计算出最匹配的key , 拿出bitmap , 在控制类 减去当前的size占用
@Override
public Bitmap get(int width, int height, Bitmap.Config config) {
int size = Util.getBitmapByteSize(width, height, config);
Key targetKey = keyPool.get(size, config);
Key bestKey = findBestKey(targetKey, size, config);
Bitmap result = groupedMap.get(bestKey);
if (result != null) {
// Decrement must be called before reconfigure.
decrementBitmapOfSize(Util.getBitmapByteSize(result), result.getConfig());
result.reconfigure(width, height,
result.getConfig() != null ? result.getConfig() : Bitmap.Config.ARGB_8888);
}
return result;
}
private Key findBestKey(Key key, int size, Bitmap.Config config) {
Key result = key;
for (Bitmap.Config possibleConfig : getInConfigs(config)) {
NavigableMap<Integer, Integer> sizesForPossibleConfig = getSizesForConfig(possibleConfig);
Integer possibleSize = sizesForPossibleConfig.ceilingKey(size);
if (possibleSize != null && possibleSize <= size * MAX_SIZE_MULTIPLE) {
if (possibleSize != size
|| (possibleConfig == null ? config != null : !possibleConfig.equals(config))) {
keyPool.offer(key);
result = keyPool.get(possibleSize, possibleConfig);
}
break;
}
}
return result;
}