关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » 安卓开发 »Android 缓存工具 DiskLruCache 学习笔记

    Android 缓存工具 DiskLruCache 学习笔记

    2015-11-03 00:00:00 出处:InfoQ
    分享

    DiskLruCache是一个十分好用的android缓存工具,我们可以从GitHub上下载其源码:https://github.com/JakeWharton/DiskLruCache

    DiskLruCache所有的数据都存储在/storage/emulated/0/Android/data/应用包名/cache/XXX文件夹中(你也可以修改,但不建议这样做,原因请继续往下看),这个是android系统默认的应用缓存位置,假如应用被删除,这个文件也会一起被删除,避免应用删除后有残留数据的问题。同时,由于数据没有存储在硬盘里,所以不会影响系统性能,在sd卡里,你可以存储任意多数据。

    由于DiskLruCache是被final修饰的,因此不可以直接通过new获得它的实例,我们使用它的open方法获得它的一个实例:
    public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)

    open方法需要四个参数,第一个是缓存文件文件的位置,通过下面的方法可得到:

      private File getDiskCacheDir(Context context, String uniqueName) {
            String cachePath;
            //假如sd卡存在并且没有被移除
            if (Environment.MEDIA_MOUNTED.equals(Environment
                    .getExternalStorageState())
                    || !Environment.isExternalStorageRemovable()) {
                cachePath = context.getExternalCacheDir().getPath();
            } else {
                cachePath = context.getCacheDir().getPath();
            }
            return new File(cachePath + File.separator + uniqueName);
        }

    第二个参数是应用程序的版本号,要传入版本号是因为假如应用升级缓存会被清除掉。通过下面的方法可以获得程序的版本号:

    private int getAppVersion(Context context) {
            try {
                PackageInfo info = context.getPackageManager().getPackageInfo(
                        context.getPackageName(), 0);
                return info.versionCode;
            } catch (NameNotFoundException e) {
                e.printStackTrace();
            }
            return 1;
        }

    第三个参数表示同一个key可以对应多少个缓存文件,一般情况下我们都是传1,这样key和缓存文件一一对应,查找和移除都会比较方便。

    第四个参数表示最大可以缓存多少字节的数据。

    打开了DiskLruCache之后,我们可以看看怎么向DiskLruCache中缓存数据:

    先来看看从网上down一张图片:

    private boolean downloadImg(final String urlStr,
                final OutputStream outputStream) {
            HttpURLConnection conn = null;
            BufferedOutputStream out = null;
            BufferedInputStream in = null;
            try {
                URL url = new URL(urlStr);
                conn = (HttpURLConnection) url.openConnection();
                in = new BufferedInputStream(conn.getInputStream(), 8 * 1024);
                out = new BufferedOutputStream(outputStream, 8 * 1024);
                int len = 0;
                while ((len = in.read()) != -1) {
                    out.write(len);
                }
                return true;
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (conn != null)
                    conn.disconnect();
                try {
                    if (out != null)
                        out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (in != null)
                        in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }

    这是一个简单的联网down图片代码,拿到图片后就可以缓存到本地了,但是对于每一个存储资源都需要有一个key,这个key要是唯一的,而且这个key 最长120个字符,且只能包括a-z,0-9,下划线以及减号,一次我们可以采用Java中的UUID来得到key,也可以使用MD5加密网址得到一个 key,我这里采用md5,方法如下:

    public class MD5Util {
    
        public final static String md5(String pwd) {
            //用于加密的字符
            char md5String[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                    'A', 'B', 'C', 'D', 'E', 'F' };
            try {
                //使用平台的默认字符集将此 String 编码为 byte序列,并将结果存储到一个新的 byte数组中
                byte[] btInput = pwd.getBytes();
    
                // 获得指定摘要算法的 MessageDigest对象,此处为MD5
                //MessageDigest类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。
                //信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值。 
                MessageDigest mdInst = MessageDigest.getInstance("MD5");
                //System.out.println(mdInst);  
                //MD5 Message Digest from SUN, <initialized>
    
                //MessageDigest对象通过使用 update方法处理数据, 使用指定的byte数组更新摘要
                mdInst.update(btInput);
                //System.out.println(mdInst);  
                //MD5 Message Digest from SUN, <in progress>
    
                // 摘要更新之后,通过调用digest()执行哈希计算,获得密文
                byte[] md = mdInst.digest();
                //System.out.println(md);
    
                // 把密文转换成十六进制的字符串形式
                int j = md.length;
                //System.out.println(j);
                char str[] = new char[j * 2];
                int k = 0;
                for (int i = 0; i < j; i++) {   //  i = 0
                    byte byte0 = md[i];  //95
                    str[k++] = md5String[byte0 >>> 4 & 0xf];    //    5  
                    str[k++] = md5String[byte0 & 0xf];   //   F
                }
    
                //返回经过加密后的字符串
                return new String(str);
    
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }

    各位看官在使用的时候记得把md5String[]中大写的字母改为小写,因为key中假如有大写字母验证会不通过。当然,你也可以修改DiskLruCache的源码从而让它支持大写字母,修改的地方:

    android缓存工具DiskLruCache学习

    现在万事俱备,我们来把图片缓存起来,由于联网是好事操作,所以要在新线程中完成,完整的方法如下:

       private void cacheImg() {
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    String key = MD5Util.md5(IMGIP);
                    try {
                        DiskLruCache.Editor editor = mDiskLruCache.edit(key);
                        if (editor != null) {
                            OutputStream out = editor.newOutputStream(0);
                            if (downloadImg(IMGIP, out)) {
                                //提交
                                editor.commit();
                            } else {
                                //撤销操作
                                editor.abort();
                            }
                        }
                        /**
                         * 这个方法用于将内存中的操作记录同步到日志文件(也就是journal文件)当中。
                         * 这个方法非常重要,因为DiskLruCache能够正常工作的前提就是要依赖于journal文件中的内容。
                         * 并不是每次写入缓存都要调用一次flush()方法的,频繁地调用并不会带来任何好处,
                         * 只会额外增加同步journal文件的时间。
                         * 比较标准的做法就是在Activity的onPause()方法中去调用一次flush()方法就可以了
                         */
                        mDiskLruCache.flush();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

    editor.newOutputStream(0);方法有一个参数,查看源码我们知道这个参数必须大于0并且小于valueCount,前文中valueCount我们已经设置为1了,所以这里只能取值0。这个时候打开你的缓存文件夹,/storage/emulated/0/Android/data/应用包名/cache/XXX,里边已经有了我们缓存的数据了:

    android缓存工具DiskLruCache学习

    好了,数据存下来了,接下来就是读取,每一个缓存文件都对应一个key,读取就是根据这个key来读取:

     private void showImg() {
            String key = MD5Util.md5(IMGIP);  
            try {
                DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
                if(snapShot!=null){
                    InputStream is = snapShot.getInputStream(0);
                    Bitmap bitmap = BitmapFactory.decodeStream(is);
                    im.setImageBitmap(bitmap);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } 
        }

    读取的时候我们最先拿到的是一个Snapshot 对象,再根据我们之前传入的参数0拿到缓存文件的流,最后把流转换为图片。

    到这里大家可能就明白了,之前的editor.newOutputStream(0);方法为什么会有一个0的参数了,相当于一个标识,读取时也传入参数0才能读到我们想要的数据。(加入我们的key与缓存文件不是一一对应,也就是我们一开始的open方法中传入的不是valueCount的值不是 1,那么一个key对应多个缓存文件大家要怎么区分?就是通过这种方式,有兴趣的同学查看源码就一目了然了)。

    下来就是清除缓存了,看方法:

    private void clearCache() {
            String key = MD5Util.md5(IMGIP);
            try {
                mDiskLruCache.remove(key);
            } catch (IOException e) {
                e.printStackTrace();
            }  
        }

    根据缓存文件的key,调用remove方法,将该缓存文件移除。

    下来是查看缓存大小:

    android缓存工具DiskLruCache学习
    像凤凰新闻客户端中显示缓存大小,这个数值我们可以通过size()方法直接拿到:

       private void getCacheSize() {
            tv.setText(mDiskLruCache.size()+"");
        }

    大家应该看到了凤凰新闻还有一个功能就是清除缓存,这个功能直接调用delete方法就能实现:

     private void deleteAll() {
            /**
             * 这个方法用于将所有的缓存数据全部删除
             * 其实只需要调用一下DiskLruCache的delete()方法就可以实现了。
             * 会删除包括日志文件在内的所有文件
             */
            try {
                mDiskLruCache.delete();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    所有功能都完成之后,大家要记得在onDestory方法中关闭DiskLruCache。

     @Override
        protected void onDestroy() {
            super.onDestroy();
            /**
             * 这个方法用于将DiskLruCache关闭掉,是和open()方法对应的一个方法。
             * 关闭掉了之后就不能再调用DiskLruCache中任何操作缓存数据的方法,
             * 通常只应该在Activity的onDestroy()方法中去调用close()方法。
             */
            try {
                mDiskLruCache.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    到此,我想大家已经基本会用这个东东了吧。

    最后奉上本文源码下载地址http://pan.baidu.com/s/1kTzSHtd

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    正版 Windows 11产品密钥怎么查找/查看?

    还有3个月,微软将停止 Windows 10 的更新

    Windows 10 终止支持后,企业为何要立即升级?

    Windows 10 将于 2025年10 月终止技术支持,建议迁移到 Windows 11

    Windows 12 发布推迟,微软正全力筹备Windows 11 25H2更新

    Linux 退出 mail的命令是什么

    Linux 提醒 No space left on device,但我的空间看起来还有不少空余呢

    hiberfil.sys文件可以删除吗?了解该文件并手把手教你删除C盘的hiberfil.sys文件

    Window 10和 Windows 11哪个好?答案是:看你自己的需求

    盗版软件成公司里的“隐形炸弹”?老板们的“法务噩梦” 有救了!

    IT头条

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    液冷服务器概念股走强,博汇、润泽等液冷概念股票大涨

    01:17

    亚太地区的 AI 驱动型医疗保健:2025 年及以后的下一步是什么?

    16:30

    智能手机市场风云:iPhone领跑销量榜,华为缺席引争议

    15:43

    大数据算法和“老师傅”经验叠加 智慧化收储粮食尽显“科技范”

    15:17

    技术热点

    SQL汉字转换为拼音的函数

    windows 7系统无法运行Photoshop CS3的解决方法

    巧用MySQL加密函数对Web网站敏感数据进行保护

    MySQL基础知识简介

    Windows7和WinXP下如何实现不输密码自动登录系统的设置方法介绍

    windows 7系统ip地址冲突怎么办?windows 7系统IP地址冲突问题的

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。