Android ImageLoader 本地缓存
本地缓存
在缓存文件时对文件名称的修改提供了两种方式,每一种方式对应了一个Java类
1) HashCodeFileNameGenerator,该类负责获取文件名称的hashcode然后转换成字符串。
2) Md5FileNameGenerator,该类把源文件的名称同过md5加密后保存。
两个类都继承了FileNameGenerator接口
在DefaultConfigurationFactory类中提供了一个工厂方法createFileNameGenerator,该方法返回了一个默认的FileNameGenerator对象:HashCodeFileNameGenerator.
public static FileNameGenerator createFileNameGenerator() { return new HashCodeFileNameGenerator(); }实现
protected final File cacheDir;//缓存文件的保存Directory protected final File reserveCacheDir;//后备缓存的Diectory,当cacheDir不存在的情况下就是用reserveCahceDir后备缓存 protected final FileNameGenerator fileNameGenerator;//文件名名称生成器
public BaseDiscCache(File cacheDir) { this(cacheDir, null); } public BaseDiscCache(File cacheDir, File reserveCacheDir) { this(cacheDir, reserveCacheDir, DefaultConfigurationFactory.createFileNameGenerator()); } public BaseDiscCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) { if (cacheDir == null) { throw new IllegalArgumentException('cacheDir' + ERROR_ARG_NULL); } if (fileNameGenerator == null) { throw new IllegalArgumentException('fileNameGenerator' + ERROR_ARG_NULL); } this.cacheDir = cacheDir; this.reserveCacheDir = reserveCacheDir; this.fileNameGenerator = fileNameGenerator; }1) 只有一个参数的构造函数只初始化了cacheDir,没有用到后备缓存,且是以HashCodeFileNameGenerator来生成目标文件的文件名。
protected File getFile(String imageUri) { String fileName = fileNameGenerator.generate(imageUri); File dir = cacheDir; if (!cacheDir.exists() && !cacheDir.mkdirs()) { if (reserveCacheDir != null && (reserveCacheDir.exists() || reserveCacheDir.mkdirs())) { dir = reserveCacheDir; } } return new File(dir, fileName); }
public boolean save(String imageUri, Bitmap bitmap) throws IOException { //获取imageUri的File对象,该对象封装了缓存路径和图片保存后的名称 File imageFile = getFile(imageUri); //获取临时保存文件的tmpFile对象 File tmpFile = new File(imageFile.getAbsolutePath() + TEMP_IMAGE_POSTFIX); OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile), bufferSize); boolean savedSuccessfully = false; try { //调用compress把bitMap压缩到tempFile中 savedSuccessfully = bitmap.compress(compressFormat, compressQuality, os); } finally { IoUtils.closeSilently(os); //如果保存成功并且tempFile的文件没有成功移动到imageFile的话,就删除temFile if (savedSuccessfully && !tmpFile.renameTo(imageFile)) { savedSuccessfully = false; } if (!savedSuccessfully) { tmpFile.delete(); } } //对bitmap进行垃圾回收 bitmap.recycle(); return savedSuccessfully; }
BaseDiscCache有两个扩展类,一个是不限制缓存大小的UnlimitedDiscCache和限制缓存时间的LimitedAgeDiscCache,其中UnlimitedDiscCache很简单它只是简单的继承了BaseDiscCache并未对BaseDiscCache做任何扩展。
LimitedAgeDiscCache该类实现了在缓存中删除被加载超过规定时间的文件:满足以下条件的时候就从缓存中删除文件:系统当前时间-文件的最新修改时间 > maxFileAge
该类提供了两个属性:
1. maxFileAge(long)设置加载的超时的最大时间,改时间在构造器冲初始化,一经初始化就不能改变(设定文件存活的最长时间,当超过这个值,就删除该文件)
2. loadingDates (Map
private void rememberUsage(String imageUri) { File file = getFile(imageUri); long currentTime = System.currentTimeMillis(); file.setLastModified(currentTime); loadingDates.put(file, currentTime); }从缓存中获取数据的方法为get(String imageUri)该类是重写BaseDiscDache方法,该方法从loadingDates中获取imageUri所代表的图片的最新更新时间loadingDate,然后拿当前时间和loadingDate做差,如果差值大于maxFileAge也就是说查过了加载的最大时间,就删除该imageUri所代表的file,并从loadingDates中的数据,当然如果map中没有imageUri就不会涉及到超时的问题,此时就把image放入map中去,具体的实现如下
@Override public File get(String imageUri) { File file = super.get(imageUri); if (file != null && file.exists()) { boolean cached; Long loadingDate = loadingDates.get(file); if (loadingDate == null) { cached = false; loadingDate = file.lastModified(); } else { cached = true; } if (System.currentTimeMillis() - loadingDate > maxFileAge) { file.delete(); loadingDates.remove(file); } else if (!cached) { loadingDates.put(file, loadingDate); } } return file; }