DiskLruCache 硬盘缓存 使用简介

简介


LruCache只是管理了内存中图片的存储与释放,如果图片从内存中被移除的话,那么又需要从网络上重新加载一次图片,这显然非常耗时。对此,Google又提供了一套硬盘缓存的解决方案:DiskLruCache(非Google官方编写,但获得官方认证)。

由于DiskLruCache并不是由Google官方编写的,所以这个类并没有被包含在Android API当中,我们需要将这个类从网上下载下来,然后手动添加到项目当中。

下载地址:http://download.csdn.net/detail/sinyu890807/7709759

下载好了源码之后,只需要在项目中新建一个libcore.io包,然后将DiskLruCache.java文件复制到这个包中即可。


缓存路径设置


虽然我们可以自由的设定使用DiskLruCache时数据的缓存位置,但是通常情况下都会将缓存的位置选择为 /sdcard/Android/data/包名/cache,因为这是存储在SD卡上且被Android系统认定为是应用程序的缓存路径,当程序被卸载的时候,这里的数据也会一起被清除掉。

另外我们也需要考虑如果这个手机没有SD卡,或者SD正好被移除了的情况,因此我们专门写一个方法来获取缓存地址,如下所示:

    /**

     * 根据传入的uniqueName(子目录)获取硬盘缓存的路径地址

     */

    public File getDiskCacheDir(Context context, String uniqueName) {

        String cachePath;

        //当SD卡【存在】或者SD卡【不可被移除】时

        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) {

            cachePath = context.getExternalCacheDir().getPath();//【SDCard/Android/data/包名/cache/】目录

        } else cachePath = context.getCacheDir().getPath();//【/data/data/包名/cache/】目录

        return new File(cachePath + File.separator + uniqueName);

    }

获取实例及初始化


DiskLruCache是不能new出实例的,如果我们要创建一个DiskLruCache的实例,则需要调用它的open()方法:

public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)

参数:数据的缓存地址,当前应用程序的版本号,同一个key可以对应多少个缓存文件(传1即可),最多可以缓存多少字节的数据。

需要注意的是,每当版本号改变,缓存路径下存储的所有数据都会被清除掉,因为DiskLruCache认为当应用程序有版本更新的时候,所有的数据都应该从网上重新获取。

一个标准的open()方法如下:

     // 获取图片缓存路径

    File cacheDir = getDiskCacheDir(context, "thumb");

    if (!cacheDir.exists()) cacheDir.mkdirs();

    // 创建DiskLruCache实例,初始化缓存数据

    try {

        mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);

    } catch (IOException e) {

        e.printStackTrace();

    }   

    /**      * 获取当前应用程序的版本号。      */     public int getAppVersion(Context context) {         try {             PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);             return info.versionCode;         } catch (NameNotFoundException e) {             e.printStackTrace();         }         return 1;     }  

MD5编码生成文件名


我们将网络图片保存到本地时,需要指定一个文件名,并且此文件名必须要和图片的URL是一一对应的,那么用什么方式实现呢?

直接使用URL来作为key?不合适,因为图片URL中可能包含一些特殊字符,这些字符有可能在命名文件时是不合法的。

最简单的做法就是将图片的URL进行MD5编码,编码后的字符串肯定是唯一的,并且只会包含0-F这样的字符,完全符合文件的命名规则。

    /**

     * 使用MD5算法对传入的key进行加密并返回。

     */

    public String hashKeyForDisk(String key) {

        String cacheKey;

        try {

            //为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值。

            MessageDigest mDigest = MessageDigest.getInstance("MD5");

            mDigest.update(key.getBytes());//使用指定的 byte 数组更新摘要

            byte[] bytes = mDigest.digest();//通过执行诸如填充之类的最终操作完成哈希计算,返回存放哈希值结果的 byte 数组

            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < bytes.length; i++) {

                String hex = Integer.toHexString(0xFF & bytes[i]);//以十六进制无符号整数形式返回一个整数参数的字符串表示形式

                if (hex.length() == 1) sb.append(‘0‘);

                sb.append(hex);

            }

            cacheKey = sb.toString();

        } catch (NoSuchAlgorithmException e) {

            cacheKey = String.valueOf(key.hashCode());

        }

        return cacheKey;

    }  

缓存的读写操作


写入缓存

写入的操作是借助DiskLruCache.Editor这个类完成的。类似地,这个类也是不能new的,需要调用DiskLruCache的edit()方法来获取实例,接口如下:

public Editor edit(String key) throws IOException  

参数key即为缓存文件的文件名

有了DiskLruCache.Editor的实例之后,我们可以调用它的newOutputStream()方法来创建一个输出流,然后把它传入到downloadUrlToStream()中就能实现下载并写入缓存的功能了。

注意newOutputStream()方法接收一个index参数,由于前面在设置valueCount的时候指定的是1,所以这里index传0就可以了。

在写入操作执行完之后,我们还需要调用一下commit()方法进行提交才能使写入生效,调用abort()方法的话则表示放弃此次写入。

读取缓存 读取主要是借助DiskLruCache的get()方法实现的,接口如下: public synchronized Snapshot get(String key) throws IOException   参数就是将图片URL进行MD5编码后的值 返回的是一个DiskLruCache.Snapshot对象 通过Snapshot的getInputStream()方法可以得到缓存文件的输入流,同样地,getInputStream()方法也需要传一个index参数,这里传入0就好。

其他API

  • 1. size()
这个方法会返回当前缓存路径下所有缓存数据的总字节数,以byte为单位,如果应用程序中需要在界面上显示当前缓存数据的总大小,就可以通过调用这个方法计算出来。
  • 2.flush()
这个方法用于将内存中的操作记录同步到日志文件(也就是journal文件)当中。 这个方法非常重要,因为DiskLruCache能够正常工作的前提就是要依赖于journal文件中的内容。并不是每次写入缓存都要调用一次flush()方法的,频繁地调用并不会带来任何好处,只会额外增加同步journal文件的时间。比较标准的做法就是在Activity的onPause()方法中去调用一次flush()方法就可以了。
  • 3.close()
这个方法用于将DiskLruCache关闭掉,是和open()方法对应的一个方法。 关闭掉了之后就不能再调用DiskLruCache中任何操作缓存数据的方法,通常只应该在Activity的onDestroy()方法中去调用close()方法。
  • 4.delete()
这个方法用于将所有的缓存数据全部删除,比如很多应用中的那个手动清理缓存功能,其实只需要调用一下DiskLruCache的delete()方法就可以实现了。
  • 5.remove(String key)
这个方法用于移除指定的缓存,我们并不应该经常去调用它,因为你完全不需要担心缓存的数据过多从而占用SD卡太多空间的问题,DiskLruCache会根据我们在调用open()方法时设定的缓存最大值来自动删除多余的缓存。只有你确定某个key对应的缓存内容已经过期,需要从网络获取最新数据的时候才应该调用remove()方法来移除缓存。

日志文件

缓存目录下会自动生成一个名为journal的日志文件,程序对每张图片的操作记录都存放在这个文件中,基本上看到journal这个文件就标志着该程序使用了DiskLruCache技术了。

其内容片断如下



前五行被称为journal文件的头。

第一行是个固定的字符串"libcore.io.DiskLruCache",标志着我们使用的是DiskLruCache技术。

第二行是DiskLruCache的版本号,这个值是恒为1的。

第三行是应用程序的版本号,我们在open()方法里传入的版本号是什么这里就会显示什么。

第四行是valueCount,这个值也是在open()方法中传入的,通常情况下都为1。

第五行是一个空行。

第六行是以一个DIRTY前缀开始的,后面紧跟着缓存图片的key。 通常我们看到DIRTY这个字样都不代表着什么好事情,意味着这是一条脏数据。 没错,每当我们调用一次DiskLruCache的edit()方法时,都会向journal文件中写入一条DIRTY记录,表示我们正准备写入一条缓存数据,但不知结果如何。然后调用commit()方法表示写入缓存成功,这时会向journal中写入一条CLEAN记录,意味着这条“脏”数据被“洗干净了”,调用abort()方法表示写入缓存失败,这时会向journal中写入一条REMOVE记录。 也就是说,每一行DIRTY的key,后面都应该有一行对应的CLEAN或者REMOVE的记录,否则这条数据就是“脏”的,会被自动删除掉。 另外,DiskLruCache会在每一行CLEAN记录的最后加上该条缓存数据的大小,以字节为单位。前面我们所学的size()方法可以获取到当前缓存路径下所有缓存数据的总字节数,其实它的工作原理就是把journal文件中所有CLEAN记录的字节数相加,求出的总合再把它返回而已。
每当我们调用get()方法去读取一条缓存数据时,就会向journal文件中写入一条READ记录。 那么你可能会担心了,如果我不停频繁操作的话,就会不断地向journal文件中写入数据,那这样journal文件岂不是会越来越大? 这倒不必担心,DiskLruCache中使用了一个redundantOpCount变量来记录用户操作的次数,每执行一次写入、读取或移除缓存的操作,这个变量值都会加1,当变量值达到2000的时候就会触发重构journal的事件,这时会自动把journal中一些多余的、不必要的记录全部清除掉,保证journal文件的大小始终保持在一个合理的范围内。

来自为知笔记(Wiz)

时间: 2024-10-14 06:20:51

DiskLruCache 硬盘缓存 使用简介的相关文章

Android DiskLruCache 硬盘缓存

概述 记得在很早之前,我有写过一篇文章Android高效加载大图.多图解决方案,有效避免程序OOM,这篇文章是翻译自Android Doc的,其中防止多图OOM的核心解决思路就是使用LruCache技术.但LruCache只是管理了内存中图片的存储与释放,如果图片从内存中被移除的话,那么又需要从网络上重新加载一次图片,这显然非常耗时.对此,Google又提供了一套硬盘缓存的解决方案:DiskLruCache(非Google官方编写,但获得官方认证).只可惜,Android Doc中并没有对Dis

DiskLruCache硬盘缓存技术详解

上次讲了使用内存缓存LruCache去加载很多图片而不造成OOM,而这种缓存的特点是在应用程序运行时管理内存中的资源(图片)的存储和释放,如果LruCache中有一张图片被释放了,再次加载该图片时需要重新从网络上下载下来,这就显得废流量不说,而且费时,网络不好的状况下用户需要等待,而且在没有网络的情况下不会显示任何数据. 那么怎样才能解决这种情况呢?答案就是加入硬盘缓存DiskLruCache. 1.什么是硬盘缓存呢? 顾名思义,就是把从网络上加载的数据存储在本地硬盘上,当再次加载这些数据时候,

硬盘缓存技术DiskLruCache技术&lt;笔记&gt;

防止多图OOM的核心解决思路就是使用LruCache技术,但LruCache只是管理了内存中图片的存储与释放,如果图片从内存中被移除的话,那么又需要从网络上重新加载一次,这显然非常耗时.因此Google又提供了一套硬盘缓存的解决方案:DiskLruCache(非Google官方编写,但获得官方认证).一般来说新闻类App从网络获取到数据后都会存入到本地缓存中,因此即使手机在没有网络的情况下依然能够加载出以前浏览过的新闻.使用的缓存技术自然是DiskLruCache.以网易新闻为例,它的Andro

硬盘缓存方案DiskLruCache源代码解析

前面研究了LruCache,它作为如今用的最多的内存缓存方案已经在非常多开源缓存框架中使用.相同的还有硬盘缓存方案也就是DiskLruCache,通常的做法就是使用内存和硬盘二级缓存. 用法 1.存储: DiskLruCache diskLruCache= open(File directory, int appVersion, int valueCount, long maxSize); DiskLruCache.Editor editor = diskLruCache.edit(key);

Android DiskLruCache完全解析,硬盘缓存的最佳方案(转)

概述 记得在很早之前,我有写过一篇文章<Android高效加载大图.多图解决方案,有效避免程序OOM>,这篇文章是翻译自Android Doc的,其中防止多图OOM的核心解决思路就是使用LruCache技术.但LruCache只是管理了内存中图片的存储与释放,如果图片从内存中被移除的话,那么又需要从网络上重新加载一次图片,这显然非常耗时.对此,Google又提供了一套硬盘缓存的解决方案:DiskLruCache(非Google官方编写,但获得官方认证).只可惜,Android Doc中并没有对

硬盘缓存方案DiskLruCache源码解析

前面研究了LruCache,它作为现在用的最多的内存缓存方案已经在很多开源缓存框架中使用,同样的还有硬盘缓存方案也就是DiskLruCache,通常的做法就是使用内存和硬盘二级缓存. 使用方法 1.存储: DiskLruCache diskLruCache= open(File directory, int appVersion, int valueCount, long maxSize); DiskLruCache.Editor editor = diskLruCache.edit(key);

Android DiskLruCache完全解析,硬盘缓存的最佳方案

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/28863651 概述 记得在很早之前,我有写过一篇文章Android高效加载大图.多图解决方案,有效避免程序OOM,这篇文章是翻译自Android Doc的,其中防止多图OOM的核心解决思路就是使用LruCache技术.但LruCache只是管理了内存中图片的存储与释放,如果图片从内存中被移除的话,那么又需要从网络上重新加载一次图片,这显然非常耗时.对此,Google又提供了一套硬

Android DiskLruCache 源代码解析 硬盘缓存的绝佳方案

转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/47251585: 本文出自:[张鸿洋的博客] 一.概述 依然是整理东西.所以最近的博客涉及的东西可能会比較老一点,会分析一些经典的框架,我觉得可能也是每一个优秀的开发人员必须掌握的东西:那么对于Disk Cache,DiskLruCache能够算佼佼者了,所以我们就来分析下其源代码实现. 对于该库的使用.推荐老郭的blog Android DiskLruCache全然解析,硬盘

Android之本地缓存——LruCache(内存缓存)与DiskLruCache(硬盘缓存)统一框架

本文参考郭霖大神的DiskLruCache解析,感兴趣的朋友可以先到http://blog.csdn.net/guolin_blog/article/details/28863651了解. 一.前言 该框架或者说库,主要是用于本地的图片缓存处理. 数据的存入 当你取到图片的元数据,会将数据存入硬盘缓存以及内存缓存中. 数据的获取 取数据的时候,先从内存缓存中取: 如果没有取到,则从硬盘缓存中取(此时如果硬盘缓存有数据,硬盘缓存会重新将数据写入内存缓存中): 如果硬盘缓存中没有取到,则从网上重新获