转载请注明本文出自xiaanming的博客(看了UIL中的苏存实现。

转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/26810303),请珍惜别人之辛勤劳动成果,谢谢!

语到缓存,平时流水线上之码农一定当这是一个伟大上之物。看罢网上各种讲缓存原理的章,总感觉那些文章说道的饶是玩具,能用呢?这次自己拿拉动您一头看了UIL这个国内外大牛都追拍的图片缓存类库的缓存处理机制。看了UIL中之休养生息存实现,才察觉实际这东西不碍事,没有太多之进程调度,没有各种内存读取控制机制、没有各种大处理。反正UIL中未单代码写的概括,连处理还简单。但是是类库这么好用,又发出诸如此类多口就此,那么坏有必要看外是怎么落实之。先了解UIL中缓存流程的规律图。

本篇文章继续为大家介绍Universal-Image-Loader这个开源的图纸加载框架,介绍的凡图片缓存策略方面的,如果大家对斯开源框架的以还未打听,大家可省自己事先写的如出一辙首文章Android
开源框架Universal-Image-Loader完全解析(一)—
基本介绍及采取,我们一般去加载大量的图片的下,都见面召开缓存策略,缓存又分为内存缓存和硬盘缓存,我前为描绘了几篇异步加载大量图片的篇章,使用的内存缓存是LruCache这个近乎,LRU是Least
Recently Used
近期最少使用算法,我们好给LruCache设定一个缓存图片的无限充分价值,它会自行帮助我们管理好缓存的图片总大小是否超越我们设定的价值,
超过就去近期起码使用的图样,而作为一个无敌的图纸加载框架,Universal-Image-Loader自然也提供了多图纸的休养存策略,下面就是来详细的牵线下

规律示意图

 

内存缓存

图片 1

 

中心有三只,分别是UI,缓存模块和数据源(网络)。它们中的关联如下:

先是我们来打探下什么是高引用和什么是故引用?

UI:请求数据,使用唯一的Key值索引Memory Cache中之Bitmap。

大引用是靠创一个对象并将这目标给予给一个援变量, 强引用有引用变量指向时永远不会见为垃圾回收。即使内存不足的时节宁愿报OOM也非受垃圾回收器回收,我们new的靶子都是青出于蓝引用

外存缓存:缓存搜索,如果会找到Key值对应之Bitmap,则回数据。否则执行第三步。

呜呼引用通过weakReference类来贯彻,它兼具很强之不确定性,如果垃圾回收器扫描到有WeakReference的靶子,就见面以那个回收释放内存

硬盘存储:使用唯一Key值对应之文件称,检索SDCard上之文书。

 

若是生针对性许文件,使用BitmapFactory.decode*艺术,解码Bitmap并返回数据,同时用数据形容副缓存。如果无对号入座文件,执行第五步。

而今我们来拘禁Universal-Image-Loader有什么内存缓存策略

下载图片:启动异步线程,从数据源下载数据(Web)。

  1. 才行使的凡高引用缓存 

  2. LruMemoryCache(这个看似就是者开源框架默认的外存缓存类,缓存的凡bitmap的强引用,下面我会从源码上面分析这个近乎)

假使下充斥成功,将数据而写副硬盘和缓存,并以Bitmap显示在UI中。

 

连接下,我们想起一下UIL蒙缓存的布置(具体的显现PART
2—ImageLoaderConfiguration详解)。重点关注注释部分,我们得以依据自己索要安排内存、磁盘缓存的贯彻。

2.施用大引用和弱引用相结合的休养存来

图片 2

  • UsingFreqLimitedMemoryCache(如果缓存的图片总量超过限定值,先去使用效率最小之bitmap)
  • LRULimitedMemoryCache(这个邪是运用的lru算法,和LruMemoryCache不同的是,他缓存的凡bitmap的故引用)
  • FIFOLimitedMemoryCache(先进先出的休养存策略,当过设定值,先去最先在缓存的bitmap)
  • LargestLimitedMemoryCache(当过缓存限定值,先去最特别的bitmap对象)
  • LimitedAgeMemoryCache(当
    bitmap加入缓存中之日跨我们设定的价,将该除去)

😉

 

UIL中的内存缓存策略

3.不过使弱引用缓存

  1. 单单下的凡大引用缓存
  • WeakMemoryCache(这个类缓存bitmap的究竟大小没有限制,唯一不足的地方即是匪安定,缓存的图纸容易让回收掉)

LruMemoryCache(这个仿佛即是以此开源框架默认的外存缓存类,缓存的凡bitmap的胜引用,下面我会从源码上面分析是类似)

 

2.采用大引用和弱引用相结合的休养生息存来

面介绍了Universal-Image-Loader所提供的具有的内存缓存的好像,当然我们啊可以使用我们自己写的外存缓存类,我们还要看要怎么将这些内存缓存投入到我们的路遭到,我们唯有需要配置ImageLoaderConfiguration.memoryCache(…),如下

UsingFreqLimitedMemoryCache(如果缓存的图形总量逾限定值,先去使用频率最小之bitmap)

ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)  
        .memoryCache(new WeakMemoryCache())  
        .build();  

LRULimitedMemoryCache(这个吧是使的lru算法,和LruMemoryCache不同的是,他缓存的凡bitmap的死亡引用)

  下面我们来分析LruMemoryCache这个看似的源代码

FIFOLimitedMemoryCache(先进先出的休养存策略,当跨越设定值,先去最先在缓存的bitmap)

package com.nostra13.universalimageloader.cache.memory.impl;  

import android.graphics.Bitmap;  
import com.nostra13.universalimageloader.cache.memory.MemoryCacheAware;  

import java.util.Collection;  
import java.util.HashSet;  
import java.util.LinkedHashMap;  
import java.util.Map;  

/** 
 * A cache that holds strong references to a limited number of Bitmaps. Each time a Bitmap is accessed, it is moved to 
 * the head of a queue. When a Bitmap is added to a full cache, the Bitmap at the end of that queue is evicted and may 
 * become eligible for garbage collection.<br /> 
 * <br /> 
 * <b>NOTE:</b> This cache uses only strong references for stored Bitmaps. 
 * 
 * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) 
 * @since 1.8.1 
 */  
public class LruMemoryCache implements MemoryCacheAware<String, Bitmap> {  

    private final LinkedHashMap<String, Bitmap> map;  

    private final int maxSize;  
    /** Size of this cache in bytes */  
    private int size;  

    /** @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */  
    public LruMemoryCache(int maxSize) {  
        if (maxSize <= 0) {  
            throw new IllegalArgumentException("maxSize <= 0");  
        }  
        this.maxSize = maxSize;  
        this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);  
    }  

    /** 
     * Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head 
     * of the queue. This returns null if a Bitmap is not cached. 
     */  
    @Override  
    public final Bitmap get(String key) {  
        if (key == null) {  
            throw new NullPointerException("key == null");  
        }  

        synchronized (this) {  
            return map.get(key);  
        }  
    }  

    /** Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue. */  
    @Override  
    public final boolean put(String key, Bitmap value) {  
        if (key == null || value == null) {  
            throw new NullPointerException("key == null || value == null");  
        }  

        synchronized (this) {  
            size += sizeOf(key, value);  
            Bitmap previous = map.put(key, value);  
            if (previous != null) {  
                size -= sizeOf(key, previous);  
            }  
        }  

        trimToSize(maxSize);  
        return true;  
    }  

    /** 
     * Remove the eldest entries until the total of remaining entries is at or below the requested size. 
     * 
     * @param maxSize the maximum size of the cache before returning. May be -1 to evict even 0-sized elements. 
     */  
    private void trimToSize(int maxSize) {  
        while (true) {  
            String key;  
            Bitmap value;  
            synchronized (this) {  
                if (size < 0 || (map.isEmpty() && size != 0)) {  
                    throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");  
                }  

                if (size <= maxSize || map.isEmpty()) {  
                    break;  
                }  

                Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();  
                if (toEvict == null) {  
                    break;  
                }  
                key = toEvict.getKey();  
                value = toEvict.getValue();  
                map.remove(key);  
                size -= sizeOf(key, value);  
            }  
        }  
    }  

    /** Removes the entry for {@code key} if it exists. */  
    @Override  
    public final void remove(String key) {  
        if (key == null) {  
            throw new NullPointerException("key == null");  
        }  

        synchronized (this) {  
            Bitmap previous = map.remove(key);  
            if (previous != null) {  
                size -= sizeOf(key, previous);  
            }  
        }  
    }  

    @Override  
    public Collection<String> keys() {  
        synchronized (this) {  
            return new HashSet<String>(map.keySet());  
        }  
    }  

    @Override  
    public void clear() {  
        trimToSize(-1); // -1 will evict 0-sized elements  
    }  

    /** 
     * Returns the size {@code Bitmap} in bytes. 
     * <p/> 
     * An entry's size must not change while it is in the cache. 
     */  
    private int sizeOf(String key, Bitmap value) {  
        return value.getRowBytes() * value.getHeight();  
    }  

    @Override  
    public synchronized final String toString() {  
        return String.format("LruCache[maxSize=%d]", maxSize);  
    }  
}  

LargestLimitedMemoryCache(当过缓存限定值,先去最老之bitmap对象)

  我们得望是看似中保障的凡一个LinkedHashMap,在LruMemoryCache构造函数中我们可以看出,我们吧那安了一个缓存图片的极度特别值maxSize,并实例化LinkedHashMap,
而从LinkedHashMap构造函数的老三独参数为ture,表示它是遵循访问顺序进行排序的,
俺们来拘禁将bitmap加入到LruMemoryCache的方法put(String
key, Bitmap value),
 第61推行,sizeOf()是算各国张图所占用的byte数,size是记录时缓存bitmap的毕竟大小,如果该key之前就缓存了bitmap,我们得以事先的bitmap减掉去,接下看trimToSize()方法,我们直接看86推行,如果手上缓存的bitmap总数小于设定值maxSize,不开另外处理,如果手上缓存的bitmap总数超过maxSize,删除LinkedHashMap中的率先只元素,size中弱化去该bitmap对应的byte数

LimitedAgeMemoryCache(当
bitmap加入缓存中之时光越我们设定的价,将该去)

 

3.只有使用弱引用缓存

我们可以看该缓存类比较简单,逻辑吗比较清楚,如果大家想清楚其他内存缓存的逻辑,可以去分析分析该源码,在这里自己简单说下FIFOLimitedMemoryCache的兑现逻辑,该类应用的HashMap来缓存bitmap的凋谢引用,然后运LinkedList来保存成功进入到FIFOLimitedMemoryCache的bitmap的胜引用,如果进入的FIFOLimitedMemoryCache的bitmap总数超限定值,直接删除LinkedList的首先只因素,所以即便贯彻了先进先出的休息存策略,其他的缓存还接近,有趣味之足错过看望。

WeakMemoryCache(这个类缓存bitmap的终究大小没有限定,唯一不足之地方就是未安定,缓存的图容易为回收掉)

 

咱们一直选择UIL中的默认配置缓存策略进行解析。

硬盘缓存

ImageLoaderConfiguration config =
ImageLoaderConfiguration.createDefault(context);

通下去就是为大家解析分析硬盘缓存的政策,这个框架为供了几乎种植普遍的复苏存策略,当然要你觉得还非符合您的渴求,你为堪协调去扩大

ImageLoaderConfiguration.createDefault(…)这个法最后是调用Builder.build()方法创建默认的配备参数的。默认的内存缓存实现是LruMemoryCache,磁盘缓存是UnlimitedDiscCache。

 

LruMemoryCache解析

  • FileCountLimitedDiscCache(可以设定缓存图片的个数,当跨越设定值,删除掉最先在到硬盘的文件)
  • LimitedAgeDiscCache(设定文件存活的无比丰富时,当过这价值,就去该公文)
  • TotalSizeLimitedDiscCache(设定缓存bitmap的极致深价值,当跨越此价值,删除最先在到硬盘的文本)
  • UnlimitedDiscCache(这个缓存类没有任何的范围)

LruMemoryCache:一种采取大引用来保存有数量限制的Bitmap的cache(在半空中少的景象,保留最近动过的Bitmap)。每次Bitmap被看时,它就是吃移位至一个班的脑壳。当Bitmap被上加至一个空中既满的cache时,在排末尾的Bitmap会被挤出来并变成适合吃GC回收的状态。

 

小心:这个cache只使高引用来保存Bitmap。

下我们不怕来分析分析TotalSizeLimitedDiscCache的源码实现

LruMemoryCache实现MemoryCache,//
而MemoryCache继承自MemoryCacheAware。(原po主用的比一直的本,现在之UIL已经没有了MemoryCacheAware这个近乎)

/******************************************************************************* 
 * Copyright 2011-2013 Sergey Tarasevich 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 *******************************************************************************/  
package com.nostra13.universalimageloader.cache.disc.impl;  

import com.nostra13.universalimageloader.cache.disc.LimitedDiscCache;  
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;  
import com.nostra13.universalimageloader.core.DefaultConfigurationFactory;  
import com.nostra13.universalimageloader.utils.L;  

import java.io.File;  

/** 
 * Disc cache limited by total cache size. If cache size exceeds specified limit then file with the most oldest last 
 * usage date will be deleted. 
 * 
 * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) 
 * @see LimitedDiscCache 
 * @since 1.0.0 
 */  
public class TotalSizeLimitedDiscCache extends LimitedDiscCache {  

    private static final int MIN_NORMAL_CACHE_SIZE_IN_MB = 2;  
    private static final int MIN_NORMAL_CACHE_SIZE = MIN_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024;  

    /** 
     * @param cacheDir     Directory for file caching. <b>Important:</b> Specify separate folder for cached files. It's 
     *                     needed for right cache limit work. 
     * @param maxCacheSize Maximum cache directory size (in bytes). If cache size exceeds this limit then file with the 
     *                     most oldest last usage date will be deleted. 
     */  
    public TotalSizeLimitedDiscCache(File cacheDir, int maxCacheSize) {  
        this(cacheDir, DefaultConfigurationFactory.createFileNameGenerator(), maxCacheSize);  
    }  

    /** 
     * @param cacheDir          Directory for file caching. <b>Important:</b> Specify separate folder for cached files. It's 
     *                          needed for right cache limit work. 
     * @param fileNameGenerator Name generator for cached files 
     * @param maxCacheSize      Maximum cache directory size (in bytes). If cache size exceeds this limit then file with the 
     *                          most oldest last usage date will be deleted. 
     */  
    public TotalSizeLimitedDiscCache(File cacheDir, FileNameGenerator fileNameGenerator, int maxCacheSize) {  
        super(cacheDir, fileNameGenerator, maxCacheSize);  
        if (maxCacheSize < MIN_NORMAL_CACHE_SIZE) {  
            L.w("You set too small disc cache size (less than %1$d Mb)", MIN_NORMAL_CACHE_SIZE_IN_MB);  
        }  
    }  

    @Override  
    protected int getSize(File file) {  
        return (int) file.length();  
    }  
}  

//public interface MemoryCache extends MemoryCacheAware{ }

  这个看似是继承LimitedDiscCache,除了少单构造函数之外,还更写了getSize()方法,返回文件的轻重,接下我们不怕来探LimitedDiscCache

脚让有持续关系图

/******************************************************************************* 
 * Copyright 2011-2013 Sergey Tarasevich 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 *******************************************************************************/  
package com.nostra13.universalimageloader.cache.disc;  

import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;  
import com.nostra13.universalimageloader.core.DefaultConfigurationFactory;  

import java.io.File;  
import java.util.Collections;  
import java.util.HashMap;  
import java.util.Map;  
import java.util.Map.Entry;  
import java.util.Set;  
import java.util.concurrent.atomic.AtomicInteger;  

/** 
 * Abstract disc cache limited by some parameter. If cache exceeds specified limit then file with the most oldest last 
 * usage date will be deleted. 
 * 
 * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) 
 * @see BaseDiscCache 
 * @see FileNameGenerator 
 * @since 1.0.0 
 */  
public abstract class LimitedDiscCache extends BaseDiscCache {  

    private static final int INVALID_SIZE = -1;  

    //记录缓存文件的大小  
    private final AtomicInteger cacheSize;  
    //缓存文件的最大值  
    private final int sizeLimit;  
    private final Map<File, Long> lastUsageDates = Collections.synchronizedMap(new HashMap<File, Long>());  

    /** 
     * @param cacheDir  Directory for file caching. <b>Important:</b> Specify separate folder for cached files. It's 
     *                  needed for right cache limit work. 
     * @param sizeLimit Cache limit value. If cache exceeds this limit then file with the most oldest last usage date 
     *                  will be deleted. 
     */  
    public LimitedDiscCache(File cacheDir, int sizeLimit) {  
        this(cacheDir, DefaultConfigurationFactory.createFileNameGenerator(), sizeLimit);  
    }  

    /** 
     * @param cacheDir          Directory for file caching. <b>Important:</b> Specify separate folder for cached files. It's 
     *                          needed for right cache limit work. 
     * @param fileNameGenerator Name generator for cached files 
     * @param sizeLimit         Cache limit value. If cache exceeds this limit then file with the most oldest last usage date 
     *                          will be deleted. 
     */  
    public LimitedDiscCache(File cacheDir, FileNameGenerator fileNameGenerator, int sizeLimit) {  
        super(cacheDir, fileNameGenerator);  
        this.sizeLimit = sizeLimit;  
        cacheSize = new AtomicInteger();  
        calculateCacheSizeAndFillUsageMap();  
    }  

    /** 
     * 另开线程计算cacheDir里面文件的大小,并将文件和最后修改的毫秒数加入到Map中 
     */  
    private void calculateCacheSizeAndFillUsageMap() {  
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                int size = 0;  
                File[] cachedFiles = cacheDir.listFiles();  
                if (cachedFiles != null) { // rarely but it can happen, don't know why  
                    for (File cachedFile : cachedFiles) {  
                        //getSize()是一个抽象方法,子类自行实现getSize()的逻辑  
                        size += getSize(cachedFile);  
                        //将文件的最后修改时间加入到map中  
                        lastUsageDates.put(cachedFile, cachedFile.lastModified());  
                    }  
                    cacheSize.set(size);  
                }  
            }  
        }).start();  
    }  

    /** 
     * 将文件添加到Map中,并计算缓存文件的大小是否超过了我们设置的最大缓存数 
     * 超过了就删除最先加入的那个文件 
     */  
    @Override  
    public void put(String key, File file) {  
        //要加入文件的大小  
        int valueSize = getSize(file);  

        //获取当前缓存文件大小总数  
        int curCacheSize = cacheSize.get();  
        //判断是否超过设定的最大缓存值  
        while (curCacheSize + valueSize > sizeLimit) {  
            int freedSize = removeNext();  
            if (freedSize == INVALID_SIZE) break; // cache is empty (have nothing to delete)  
            curCacheSize = cacheSize.addAndGet(-freedSize);  
        }  
        cacheSize.addAndGet(valueSize);  

        Long currentTime = System.currentTimeMillis();  
        file.setLastModified(currentTime);  
        lastUsageDates.put(file, currentTime);  
    }  

    /** 
     * 根据key生成文件 
     */  
    @Override  
    public File get(String key) {  
        File file = super.get(key);  

        Long currentTime = System.currentTimeMillis();  
        file.setLastModified(currentTime);  
        lastUsageDates.put(file, currentTime);  

        return file;  
    }  

    /** 
     * 硬盘缓存的清理 
     */  
    @Override  
    public void clear() {  
        lastUsageDates.clear();  
        cacheSize.set(0);  
        super.clear();  
    }  


    /** 
     * 获取最早加入的缓存文件,并将其删除 
     */  
    private int removeNext() {  
        if (lastUsageDates.isEmpty()) {  
            return INVALID_SIZE;  
        }  
        Long oldestUsage = null;  
        File mostLongUsedFile = null;  

        Set<Entry<File, Long>> entries = lastUsageDates.entrySet();  
        synchronized (lastUsageDates) {  
            for (Entry<File, Long> entry : entries) {  
                if (mostLongUsedFile == null) {  
                    mostLongUsedFile = entry.getKey();  
                    oldestUsage = entry.getValue();  
                } else {  
                    Long lastValueUsage = entry.getValue();  
                    if (lastValueUsage < oldestUsage) {  
                        oldestUsage = lastValueUsage;  
                        mostLongUsedFile = entry.getKey();  
                    }  
                }  
            }  
        }  

        int fileSize = 0;  
        if (mostLongUsedFile != null) {  
            if (mostLongUsedFile.exists()) {  
                fileSize = getSize(mostLongUsedFile);  
                if (mostLongUsedFile.delete()) {  
                    lastUsageDates.remove(mostLongUsedFile);  
                }  
            } else {  
                lastUsageDates.remove(mostLongUsedFile);  
            }  
        }  
        return fileSize;  
    }  

    /** 
     * 抽象方法,获取文件大小 
     * @param file 
     * @return 
     */  
    protected abstract int getSize(File file);  
}  

图片 3

  以构造方法中,第69推行有一个措施calculateCacheSizeAndFillUsageMap(),该法是精打细算cacheDir的文件大小,并以文件和文件之最终修改时加入到Map中

 

LruMemoryCache.get(…)

接下来是以文件参加硬盘缓存的点子put(),在106实施判断时文件之缓存总数加上即将要加入缓存的文件大小是否超缓存设定值,如果超过了执行removeNext()方法,接下便来看看这个点子的求实贯彻,150-167遭遇觅有首批在硬盘的文书,169-180遭以其自文本硬盘中删去,并回该文件的高低,删除成功之后成员变量cacheSize需要减少改文件大小。

自身深信不疑接下你看看就段代码的上会及自身平惊讶于代码的简约,代码中除老判断,就是使synchronized进行共同控制。

FileCountLimitedDiscCache这个看似实现逻辑跟TotalSizeLimitedDiscCache是一样的,区别在getSize()方法,前者返回1,表示也文件反复是1,后者返回文件的大小。

图片 4

等自我形容了了这篇文章,我才发觉FileCountLimitedDiscCache和TotalSizeLimitedDiscCache在风靡的源码中已去除了,加入了LruDiscCache,由于自家之凡前的源码,所以我呢非转移了,大家而想只要了解LruDiscCache可以去看时的源码,我这边就无介绍了,还好外存缓存的没有变化,下面分析的是流行的源码中的局部,我们以运着可因为不自行安排硬盘缓存策略,直接用DefaultConfigurationFactory中的即行了

😉

俺们看DefaultConfigurationFactory这个仿佛的createDiskCache()方法

咱们见面好奇,这不是就是简单简单单将Bitmap从map中得下呢?但LruMemoryCache声称保留在上空有限的场面下封存最近下过之Bitmap。不急急,让我们细细观察一下map。他是一个LinkedHashMap型的靶子。

/** 
 * Creates default implementation of {@link DiskCache} depends on incoming parameters 
 */  
public static DiskCache createDiskCache(Context context, FileNameGenerator diskCacheFileNameGenerator,  
        long diskCacheSize, int diskCacheFileCount) {  
    File reserveCacheDir = createReserveDiskCacheDir(context);  
    if (diskCacheSize > 0 || diskCacheFileCount > 0) {  
        File individualCacheDir = StorageUtils.getIndividualCacheDirectory(context);  
        LruDiscCache diskCache = new LruDiscCache(individualCacheDir, diskCacheFileNameGenerator, diskCacheSize,  
                diskCacheFileCount);  
        diskCache.setReserveCacheDir(reserveCacheDir);  
        return diskCache;  
    } else {  
        File cacheDir = StorageUtils.getCacheDirectory(context);  
        return new UnlimitedDiscCache(cacheDir, reserveCacheDir, diskCacheFileNameGenerator);  
    }  
}  

LinkedHashMap中之get()方法不但返回所匹配的价值,并且在回前还会见拿所匹配的key对应的entry调整在列表中之次第(LinkedHashMap使用对链表来保存数据),让它们地处列表的最后。当然,这种场面必是于LinkedHashMap中accessOrder==true的图景下才生效之,反的便是get()方法无会见变动为匹配的key对应的entry在列表中之岗位。

  如果我们以ImageLoaderConfiguration中配置了diskCacheSize和diskCacheFileCount,他就算运的凡LruDiscCache,否则用的是UnlimitedDiscCache,在新型的源码中还有一个硬盘缓存类可以安排,那便是LimitedAgeDiscCache,可以当ImageLoaderConfiguration.diskCache(…)配置

图片 5

 

图片 6

今天即令让大家大快朵颐到此,有免亮的地方在底下留言,我会尽量为大家解答的,下同样篇稿子我以持续再深切的辨析这框架,希望大家继续关心!

😉

代码第369尽的recordAccess()就是调整entry在列表中的职位,其实就算是双料朝向链表的调。它判断accessOrder

。到如今我们就是明白LruMemoryCache使用LinkedHashMap来缓存数据,在LinkedHashMap.get()方法执行后,LinkedHashMap中entry的逐条会拿走调整。那么我们怎么确保最近以的宗无见面让去除呢?接下,让咱省,,,

LruMemoryCache.put(…)

瞩目到代码第62行负之size+= sizeOf(key,
value),这个size是呀也?我们注意到在第69履行有一个trimToSize(maxSize),trimToSize(…)这个函数就是为此来界定LruMemoryCache的分寸不要超过用户限定的尺寸,cache的尺寸由用户在LruMemoryCache刚开始初始化的时段限定。//map.put()的返值如果非呢空,说明有和key对应之entry,put操作只是更新原有key对应的entry

图片 7

图片 8

😉

实际不难想到,当Bitmap缓存的大小超过原来设定的maxSize时应该是以trimToSize(…)这个函数中成功的。这个函数做的业务也大概,遍历map,将盈余的项(代码中针对许toEvict)剔除掉,直到当前cache的轻重缓急相当于或小于限定的大大小小。

😉

这儿我们会产生一个道,为什么遍历一下尽管好用用最少的bitmap缓存给删除,不会见误删到近年来以的bitmap缓存吗?首先,我们设知,LruMemoryCache定义的近年动是负最近于是get或put方式操作及的bitmap缓存。其次,之前我们直到LruMemoryCache的get操作实际是透过该中间字段LinkedHashMap.get(…)实现的,当LinkedHashMap的accessOrder==true时,每一样涂鸦get或put操作都见面将所操作项(图备受第3起)移动到链表的尾(见下图,链表头被当是起码使用的,链表尾被认为是最常使用的。),每一样浅操作及之起我们还当它是近日用了之,当内存不够的下吃删去的优先级最低。需要注意的凡相同开始之LinkedHashMap链表是按照插的顺序构成的,也不怕是首先单插入的起就于链表头,最后一个插入的即以链表尾。假设只要去图中的1,2项就能让LruMemoryCache小于原先限定的轻重,那么我们若从链表头遍历下去(从1→最终一宗)那么就是可去除使用最少之项了。

图片 9

由来,我们就是掌握了LruMemoryCache缓存的全原理,包括他怎么put、get、剔除一个要素的底国策。接下去,我们若开分析默认的磁盘缓存策略了。

UIL中之磁盘缓存策略

譬如说新浪微博、花瓣这种用得加载很多图形,本来图片的加载就慢了,如果下次开拓的时还待更同不好下充斥上次都出了之图纸,相信用户的流量会被她们之叫骂声很响亮。对于图片很多的应用,一个吓的磁盘缓存直接控制了动用在用户手机的存在时间。我们团结一心实现磁盘缓存,要考虑的顶多,幸好UIL提供了几乎种普遍的磁盘缓存策略,当然如果你认为还非合乎您的求,你吧足以协调去扩大

FileCountLimitedDiscCache(可以设定缓存图片的个数,当跨越设定值,删除掉最先在到硬盘的文书)

LimitedAgeDiscCache(设定文件存活的极致丰富时,当跨越这个价值,就去该公文)

TotalSizeLimitedDiscCache(设定缓存bitmap的尽深价值,当跨越此价,删除最先在到硬盘的文本)

UnlimitedDiscCache(这个缓存类没有其余的限定)

在UIL中发生正在比完好的仓储策略,根据预先指定的长空尺寸,使用效率(生命周期),文件个数的束缚规范,都存有对应的贯彻政策。最基础之接口DiscCacheAware和抽象类BaseDiscCache

UnlimitedDiscCache解析

UnlimitedDiscCache实现disk
cache接口,是ImageLoaderConfiguration中默认的磁盘缓存处理。用它们的下,磁盘缓存的尺寸是休受限的。

对接下我们来探实现UnlimitedDiscCache的源代码,通过源代码我们发现他其实就算是延续了BaseDiscCache,这个看似中尚未落实和谐非常的方法,也没有更写什么,那么我们便直看BaseDiscCache这个看似。在条分缕析这个近乎之前,我们事先考虑自己实现一个磁盘缓存需要开多少辛苦的事务:

1、图片的命名会不会见再。你未曾章程知道用户下载的图形原始之文书称是什么的,因此特别可能因文件还名将中的图样为覆盖掉了。

2、当用卡顿或网络延迟的时,同一摆图数给下载。

3、处理图片写副磁盘可能碰到的延期和旅问题。

BaseDiscCache构造函数

率先,我们看一下BaseDiscCache的构造函数:

cacheDir:文件缓存目录

reserveCacheDir:备用的文书缓存目录,可以啊null。它只有当cacheDir不克因此之时节才发出因此。

fileNameGenerator:文件名生成器。为缓存的文件生成文书称。

图片 10

😉

咱得望一个fileNameGenerator,接下我们来了解UIL具体是怎生成不重复的文书称之。UIL中产生3种文件命名策略,这里我们惟有针对默认的文件称策略进行辨析。默认的文本命名策略在DefaultConfigurationFactory.createFileNameGenerator()。它是一个HashCodeFileNameGenerator。真的是您不意的粗略,就是使用String.hashCode()进行文件称之变更。

图片 11

BaseDiscCache.save()

剖析了了命名策略,再拘留一下BaseDiscCache.save(…)方法。注意到第2实行有一个getFile()函数,它最主要用来转移一个对缓存目录中之公文,在是函数里面调用了刚介绍了的fileNameGenerator来转文书称。注意第3执的tmpFile,它是故来描写入bitmap的临时文件(见第8履行),然后就是将这个文件于删除了。大家也许会见纳闷,为什么在save()函数里面没有看清要描绘副的bitmap文件是否留存的判断,我们不由得要看看UIL中是不是发对她进行判断。还记得我们以《》介绍的,UIL加载图片的相似流程是先行判断内存中是否出照应的Bitmap,再判断磁盘(disk)中是不是发生,如果没有就于网络被加载。最后根据本在UIL中之布置判断是否要缓存Bitmap到内存还是磁盘中。也就是说,当需要调用BaseDiscCache.save(…)之前,其实早已判定了这文件未以磁盘中。

图片 12

😉

BaseDiscCache.get()

BaseDiscCache.get()方法中调用了BaseDiscCache.getFile(…)方法,让咱来分析一下此以头里碰过的函数。
第2实施就是是下fileNameGenerator生成一个唯一的文本称。第3~8尽是指定缓存目录,这时候你虽可以掌握地看出cacheDir和reserveCacheDir之间的涉及了,当cacheDir不可用之早晚,就是用reserveCachedir作为缓存目录了。

终极回到一个对准文件的对象,但是如果留意当File类型的目标对的文件不在时时,file会为null,而无是报错。

图片 13

😉

总结

今,我们既分析了UIL的缓存机制。其实从UIL的缓存机制的实现并无是杀复杂,虽然发生各种缓存机制,但是简单地说:外存缓存其实就是是利用Map接口的靶子在内存中进行缓存,可能产生异之贮存机制。磁盘缓存其实就是将文件写副磁盘

相关文章