Glide 源碼分析之 BitmapPool

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


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 7.1 壓縮圖片 一、基礎(chǔ)知識(shí) 1、圖片的格式 jpg:最常見的圖片格式。色彩還原度比較好,可以支持適當(dāng)壓縮后保持...
    AndroidMaster閱讀 2,717評(píng)論 0 13
  • 所有知識(shí)點(diǎn)已整理成app app下載地址 J2EE 部分: 1.Switch能否用string做參數(shù)? 在 Jav...
    侯蛋蛋_閱讀 2,713評(píng)論 1 4
  • ImageLoader簡(jiǎn)單使用 ImageLoader的二級(jí)分包主要由cache、core和utils組成,三者分...
    正規(guī)程序員閱讀 630評(píng)論 0 50
  • 我是一個(gè)90后,面對(duì)自己這個(gè)尷尬的年齡,即將奔三的我們都知道自己已經(jīng)不年輕呢,因?yàn)槲沂且粋€(gè)即將臨盆的產(chǎn)婦,...
    兮兮_d9f8閱讀 1,965評(píng)論 0 1
  • 當(dāng)我再次為了大話西游進(jìn)入影院時(shí),也已經(jīng)記不清為了這部情懷的老片,觀影多少次。大概是因?yàn)樗^懷舊情懷產(chǎn)生時(shí)候,這部小...
    586c75b10b74閱讀 408評(píng)論 0 6

友情鏈接更多精彩內(nèi)容