美文网首页
Glide 源码分析之 BitmapPool

Glide 源码分析之 BitmapPool

作者: 坚持编程_lyz | 来源:发表于2018-03-26 06:03 被阅读164次

    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;
        }
    
    
    

    相关文章

      网友评论

          本文标题:Glide 源码分析之 BitmapPool

          本文链接:https://www.haomeiwen.com/subject/darlcftx.html