bitmap的緩存
在build Glide 時(shí) 會(huì)初始化根據(jù)版本不同會(huì)選擇一個(gè)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 就會(huì)創(chuàng)建一個(gè)默認(rèn)的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: 負(fù)責(zé)控制緩存
LruPoolStrategy : 他的實(shí)現(xiàn)類 , 負(fù)責(zé)真正的緩存bitmap
默認(rèn)每次在put的時(shí)候 , 都會(huì)累計(jì)內(nèi)存用量 , 判斷如果當(dāng)前使用量大于允許的最大內(nèi)存就會(huì)移除鏈表的表尾, 最新的默認(rèn)會(huì)移動(dòng)到表頭;這就是最近最少使用算法;
//可以設(shè)置緩存的大小maxSize , 有2個(gè)默認(rèn)的策略實(shí)現(xiàn),第一個(gè)真正緩存功能的實(shí)現(xiàn)類 , LruBitmapPool 只是轉(zhuǎn)發(fā)類 , 真正實(shí)現(xiàn)緩存是他 LruPoolStrategy
第二個(gè)允許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 是個(gè)枚舉, 把默認(rèn)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 他的實(shí)現(xiàn)思路;
以put 第二行 , 以bitmap的占用大小 和 他的bitmap像素類型 ,讓一個(gè)key對(duì)象來包裹 , 封裝成GroupedLinkedMap的key了, 依靠 自定義的 linkedHashMap , 把匹配的取出來并設(shè)置成表頭;
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 占用內(nèi)存大小
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 方法 , 默認(rèn)先去隊(duì)列里找 , 如果不為空就取出來 ,然后從新賦值新的屬性 , 以復(fù)用對(duì)象 , 真是一點(diǎn)內(nèi)存(多創(chuàng)建一個(gè)對(duì)象)都不浪費(fèi);
public Key get(int size, Bitmap.Config config) {
Key result = get();
result.init(size, config);
return result;
}
//隊(duì)列為空才創(chuàng)建新的
protected T get() {
T result = keyPool.poll();
if (result == null) {
result = create();
}
return result;
}
來看取bitmap , 計(jì)算出最匹配的key , 拿出bitmap , 在控制類 減去當(dāng)前的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;
}