Android -- ImageLoader本地缓存

简介:

传送门                                                                                 

Android -- ImageLoader简析》  http://www.cnblogs.com/yydcdut/p/4008097.html

本地缓存                                                                              

在缓存文件时对文件名称的修改提供了两种方式,每一种方式对应了一个Java类

1)  HashCodeFileNameGenerator,该类负责获取文件名称的hashcode然后转换成字符串。

2)  Md5FileNameGenerator,该类把源文件的名称同过md5加密后保存。

两个类都继承了FileNameGenerator接口

在DefaultConfigurationFactory类中提供了一个工厂方法createFileNameGenerator,该方法返回了一个默认的FileNameGenerator对象:HashCodeFileNameGenerator.

public static FileNameGenerator createFileNameGenerator() {  
        return new HashCodeFileNameGenerator();  
    }

实现                                                                                   

首先定义了DiscCacheAware接口,该接口提供了如下方法

  • File  getFileDectory()   返回磁盘缓存的根目录
  • File  get(String imageUri)  根据uri从缓存中获取图片
  • boolean  save(String  imageUri,InputStream iamgeStream,IoUtils.CopyListener listener)  把图片保存在磁盘缓存上
  • boolean  save(String  imageUri,Bitmap bitmap)  保存bitmap对象到磁盘缓存上
  • boolean  remove(imageUri)  根据imageUri删除文件
  • void  close()  关闭磁盘缓存,释放资源
  • void  clear()  清空磁盘缓存

然后定义了另外一个没方法的接口DiskCache,该接口只是简单的继承了DiscCacheAware接口。

BaseDiscCache实现了DiskCache,该类是个抽象类,该类定义了磁盘缓冲区的以下的属性:

1)  默认的缓存大小为32k

2)  默认压缩后的图片格式为PNG(作为Bitmap的compress方法的第一个参数)

3)  默认压缩后图片显示的质量为100,也就是压缩率为0,不进行压缩(作为compress的第二个参数)

提供了修改压缩图片格式和压缩率以及修改缓存大小的set方法。同时该类还封装了以下三个属性

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来生成目标文件的文件名。

2)  两个参数的构造器除了cacheDir和HashCodefileNameGenerator外,也可以初始化后备缓存

3)  三个参数的构造器要求必须初始化cacheDir并且必须初始化filenNameGenerator否则就报异常

get(String imageUri)                                                                

复制代码
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);  
    }
复制代码

save(String imageUri, Bitmap bitmap)                                            

复制代码
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

LimitedAgeDiscCache                                                                

该类提供了两个属性:

1.  maxFileAge(long)设置加载的超时的最大时间,改时间在构造器冲初始化,一经初始化就不能改变(设定文件存活的最长时间,当超过这个值,就删除该文件)

2.  loadingDates (Map<File,long>),该属性是一个map类型的对象,key保存的要缓存的图片文件,而value保存的是调用save方法是系统的当前时间,具体向loadingDates填充数据是在下面的rememberUsage方法中实现的,该方法在类中两个save方法中调用,首先调用父类的save方法,然后在调用此方法

复制代码
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;  
    }
复制代码



本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/4077521.html,如需转载请自行联系原作者
相关文章
|
6月前
|
存储 缓存 Android开发
安卓Jetpack Compose+Kotlin, 使用ExoPlayer播放多个【远程url】音频,搭配Okhttp库进行下载和缓存,播放完随机播放下一首
这是一个Kotlin项目,使用Jetpack Compose和ExoPlayer框架开发Android应用,功能是播放远程URL音频列表。应用会检查本地缓存,如果文件存在且大小与远程文件一致则使用缓存,否则下载文件并播放。播放完成后或遇到异常,会随机播放下一首音频,并在播放前随机设置播放速度(0.9到1.2倍速)。代码包括ViewModel,负责音频管理和播放逻辑,以及UI层,包含播放和停止按钮。
|
缓存 Android开发
Android Studio中如何清理gradle缓存
Android Studio中如何清理gradle缓存
|
缓存 Android开发
Android - 手机下载的缓存视频在文件管理怎么找不到?
Android - 手机下载的缓存视频在文件管理怎么找不到?
1563 0
Android - 手机下载的缓存视频在文件管理怎么找不到?
|
4月前
|
缓存 安全 Android开发
Android经典实战之用Kotlin泛型实现键值对缓存
本文介绍了Kotlin中泛型的基础知识与实际应用。泛型能提升代码的重用性、类型安全及可读性。文中详细解释了泛型的基本语法、泛型函数、泛型约束以及协变和逆变的概念,并通过一个数据缓存系统的实例展示了泛型的强大功能。
42 2
|
2月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
56 15
Android 系统缓存扫描与清理方法分析
|
3月前
|
存储 缓存 Android开发
Android RecyclerView 缓存机制深度解析与面试题
本文首发于公众号“AntDream”,详细解析了 `RecyclerView` 的缓存机制,包括多级缓存的原理与流程,并提供了常见面试题及答案。通过本文,你将深入了解 `RecyclerView` 的高性能秘诀,提升列表和网格的开发技能。
73 8
|
5月前
|
缓存 编解码 安全
Android经典面试题之Glide的缓存大揭秘
Glide缓存机制包括内存和硬盘缓存。内存缓存使用弱引用的ActiveResources和LRU策略,硬盘缓存利用DiskLruCache。Engine.load方法首先尝试从内存和弱引用池加载,然后从LRU缓存中加载图片,增加引用计数并移出LRU。若缓存未命中,启动新任务或加入现有任务。内存大小根据设备内存动态计算,限制在0.4以下。DiskLruCache使用自定义读写锁,保证并发安全,写操作通过锁池管理,确保高效。
123 0
|
7月前
|
XML 缓存 Java
Android App开发之利用Glide实现图片的三级缓存Cache讲解及实战(附源码 超详细必看 简单易懂)
Android App开发之利用Glide实现图片的三级缓存Cache讲解及实战(附源码 超详细必看 简单易懂)
323 0
|
缓存 JSON Java
java 实现读取txt文件,反射创建对象,android 手机缓存文件目录
java 实现读取txt文件,反射创建对象,android 手机缓存文件目录
449 1
java 实现读取txt文件,反射创建对象,android 手机缓存文件目录
|
缓存 Java Android开发
Android C++ 系列:JNI 调用时缓存字段和方法 ID
通常我们通过 FindClass 、GetFieldID、GetMethodID 去找到对应的信息也是耗时操作,如果方法被频繁调用(特别是像音视频处理时循环的调用JNI方法传递音视频数据),每次都去查找对应的类和方法ID会很耗性能,所以我们必须将它们缓存起来,达到只创建一次,后面直接使用缓存内容的效果。
158 0