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的源码从而让它支持大写字母,修改的地方:



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

    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,里边已经有了我们缓存的数据了:

好了,数据存下来了,接下来就是读取,每一个缓存文件都对应一个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方法,将该缓存文件移除。

下来是查看缓存大小:



像凤凰新闻客户端中显示缓存大小,这个数值我们可以通过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

版权声明:本文为博主原创文章,未经博主允许不得转载。若有错误地方,还望批评指正,不胜感激。

三分钟学会缓存工具DiskLruCache的更多相关文章

  1. 三分钟学会使用Derby数据库

    Derby数据库是一个纯用Java实现的内存数据库,属于Apache的一个开源项目.由于是用Java实现的,所以可以在任何平台上运行:另外一个特点是体积小,免安装,java1.6开始集成了derby数 ...

  2. 三分钟学会@Autowired@Qualifier@Primary注解

    三分钟学会@Autowired@Qualifier@Primary注解 2018.10.08 20:24 154浏览 今天主要简单的跟大家介绍一下spring自动装配相关的@Autowired,@Qu ...

  3. [转]三分钟学会.NET Core Jwt 策略授权认证

    [转]三分钟学会.NET Core Jwt 策略授权认证 一.前言# 大家好我又回来了,前几天讲过一个关于Jwt的身份验证最简单的案例,但是功能还是不够强大,不适用于真正的项目,是的,在真正面对复杂而 ...

  4. 中小研发团队架构实践之生产环境诊断工具WinDbg 三分钟学会.NET微服务之Polly 使用.Net Core+IView+Vue集成上传图片功能 Fiddler原理~知多少? ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一) C#程序中设置全局代理(Global Proxy) WCF 4.0 使用说明 如何在IIS上发布,并能正常访问

    中小研发团队架构实践之生产环境诊断工具WinDbg 生产环境偶尔会出现一些异常问题,WinDbg或GDB是解决此类问题的利器.调试工具WinDbg如同医生的听诊器,是系统生病时做问题诊断的逆向分析工具 ...

  5. 三分钟学会Redis在.NET Core中做缓存中间件

    大家好,今天给大家说明如何在.NET Core中使用Redis,我们在想要辩论程序的好与坏,都想需要一个可视化工具,我经常使用的是一位国内大牛开发的免费工具,其Github地址为: https://g ...

  6. [计划任务 - Linux]三分钟学会cron

    cron——计划任务,是任务在约定的时间执行已经计划好的工作,是一个linux下的定时执行工具,可以在无需人工干预的情况下运行作业. 也就是说cron只适合于linux系统,用windows电脑的同学 ...

  7. 三分钟学会funsioncharts

    由于项目需求需要做一个报表,选择FusionCharts作为工具使用.由于以前没有接触过报表,网上也没有比较详细的fusionCharts教程,所以决定好好研究FusionCharts,同时做一个比较 ...

  8. 三分钟学会.NET微服务之Polly

    熔断降级是一个非常重要的概念,我们先说一下什么是熔断降级,咱们都知道服务发现,一个有问题的服务器没来得急注销过一会就崩溃掉了,那么我们的请求就有可能访问一个已经崩溃的服务器,那么就会请求失败,因为已经 ...

  9. 小兔Java教程 - 三分钟学会Java文件上传

    今天群里正好有人问起了Java文件上传的事情,本来这是Java里面的知识点,而我目前最主要的精力还是放在了JS的部分.不过反正也不麻烦,我就专门开一贴来聊聊Java文件上传的基本实现方法吧. 话不多说 ...

随机推荐

  1. 在MVC或WEBAPI中记录每个Action的执行时间和记录下层方法调用时间

    刚才在博客园看了篇文章,http://www.cnblogs.com/cmt/p/csharp_regex_timeout.html  突然联想到以前遇到的问题,w3wp进程吃光CPU都挂起IIS进程 ...

  2. webkit javascript

    http://www.infoq.com/cn/news/2013/02/douglas-interview http://blog.csdn.net/horkychen/article/detail ...

  3. Stanford CoreNLP--常量定义

    在运行Stanford CoreNLP过程中会用到tokenize,pos等参数,这些以常量形式定义在edu.stanford.nlp.pipeline.Annotator中,具体如下: /** * ...

  4. WordPress 全方位优化指南(上)

    作为一个全面的 WordPress 性能优化教程,本文旨在帮助读者排查 WordPress 网站的性能问题,同时也提供网站前端优化加速的建议. 如果你曾经遇到过 WordPress 管理界面加载缓慢. ...

  5. Swifter初体验;按照惯例,来一个Swift版本的:iOS图片验证码?

    不多解释,上图,上代码:代码

  6. 【POJ 3162】 Walking Race (树形DP-求树上最长路径问题,+单调队列)

    Walking Race   Description flymouse's sister wc is very capable at sports and her favorite event is ...

  7. com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: SELECT command denied to user’

    Linux环境 Mysql+Hibernate command denied to user 错误 错误信息 如下: com.mysql.jdbc.exceptions.jdbc4.MySQLSynt ...

  8. 一起啃PRML - 1.2.3 Bayesian probabilities 贝叶斯概率

    一起啃PRML - 1.2.3 Bayesian probabilities 贝叶斯概率 @copyright 转载请注明出处 http://www.cnblogs.com/chxer/ 这一节简单讲 ...

  9. 知乎上关于c和c++的一场讨论_看看高手们的想法

    为什么很多开源软件都用 C,而不是 C++ 写成? 余天升 开源社区一直都不怎么待见C++,自由软件基金会创始人Richard Stallman认为C++有语法歧义,这样子没有必要.非常琐碎还会和C不 ...

  10. 【转】Android bluetooth介绍(三): 蓝牙扫描(scan)设备分析

    原文网址:http://blog.csdn.net/xubin341719/article/details/38584469 关键词:蓝牙blueZ  A2DP.SINK.sink_connect.s ...