磁盘缓存对于UniversalImageloader也是至关重要的,我们总不能每次显示图片都要去网络获取吧,即使有内存缓存,当重启手机,或者内存缓存被清理,那么还是要从网络上去获取,这就是磁盘缓存的意义。
框架中对于磁盘缓存的抽象是DiskCache ,我们先看一下定义:
public interface DiskCache { /** * 返回缓存文件夹 */ File getDirectory(); /** * 根据图片Uri从缓存中取出图片 */ File get(String imageUri); /** * 图片保存到磁盘缓存 */ boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException; /** * 图片保存到磁盘缓存 */ boolean save(String imageUri, Bitmap bitmap) throws IOException; /** * 从磁盘缓存删除图片 */ boolean remove(String imageUri); /** 关闭磁盘缓存,并清理资源 */ void close(); /** 清空图片磁盘缓存 */ void clear(); }
BaseDiskCache 为我们提供了默认实现,开发者需要继承它,它里面有一点需要注点意的,其他代码很简单,只不过作为基类为abstract ,这也意味着框架强制你继承这个类,虽然基类实现了所有的方法,自己看源码吧,很简单
protected final File cacheDir; protected final File reserveCacheDir;
UnlimitedDiskCache 直接实现BaseDiskCache,这里不讲了
LimitedAgeDiskCache :Cache which deletes files which were loaded more than defined time. Cache size is unlimited. 这是源码注释,意思是,超过某个时刻,就会被删除,我们看一下具体实现,看注释吧,不解释,很简单
public class LimitedAgeDiskCache extends BaseDiskCache { private final long maxFileAge;//毫秒为单位 //保存每个图片文件被缓存到磁盘上的事件 private final Map<File, Long> loadingDates = Collections.synchronizedMap(new HashMap<File, Long>()); public LimitedAgeDiskCache(File cacheDir, long maxAge) { this(cacheDir, null, DefaultConfigurationFactory.createFileNameGenerator(), maxAge); } public LimitedAgeDiskCache(File cacheDir, File reserveCacheDir, long maxAge) { this(cacheDir, reserveCacheDir, DefaultConfigurationFactory.createFileNameGenerator(), maxAge); } public LimitedAgeDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator, long maxAge) { super(cacheDir, reserveCacheDir, fileNameGenerator); this.maxFileAge = maxAge * 1000; // to milliseconds } /** * 和一般的磁盘缓存一下,使用懒删除,就是访问的时候才去检查是否过期 */ @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();//图片的last modified time } else { cached = true; } if (System.currentTimeMillis() - loadingDate > maxFileAge) { file.delete();//超过时限就删除 loadingDates.remove(file); } else if (!cached) { loadingDates.put(file, loadingDate); } } return file; } @Override public boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException { boolean saved = super.save(imageUri, imageStream, listener); rememberUsage(imageUri); return saved; } @Override public boolean save(String imageUri, Bitmap bitmap) throws IOException { boolean saved = super.save(imageUri, bitmap); rememberUsage(imageUri); return saved; } @Override public boolean remove(String imageUri) { loadingDates.remove(getFile(imageUri)); return super.remove(imageUri); } @Override public void clear() { super.clear(); loadingDates.clear(); } /** * 对最后的访问时间做了一个缓存,这只是为了方便而已 */ private void rememberUsage(String imageUri) { File file = getFile(imageUri); long currentTime = System.currentTimeMillis(); file.setLastModified(currentTime); loadingDates.put(file, currentTime); } }
还有一个包com.nostra13.universalimageloader.cache.disc.impl.ext , 这个包也是实现了一种磁盘缓存叫LruDiskCache, 它把Android源码直接拷贝了进来, DiskLruCache依赖StrictLineReader 和Util, 当然,框架的LruDiskCache对DiskLruCache做了一层包装
到此磁盘缓存就算完成了,其实很简单