三分钟学会缓存工具DiskLruCache
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();
}
}
到此,我想大家已经基本会用这个东东了吧。
版权声明:本文为博主原创文章,未经博主允许不得转载。若有错误地方,还望批评指正,不胜感激。
三分钟学会缓存工具DiskLruCache的更多相关文章
- 三分钟学会使用Derby数据库
Derby数据库是一个纯用Java实现的内存数据库,属于Apache的一个开源项目.由于是用Java实现的,所以可以在任何平台上运行:另外一个特点是体积小,免安装,java1.6开始集成了derby数 ...
- 三分钟学会@Autowired@Qualifier@Primary注解
三分钟学会@Autowired@Qualifier@Primary注解 2018.10.08 20:24 154浏览 今天主要简单的跟大家介绍一下spring自动装配相关的@Autowired,@Qu ...
- [转]三分钟学会.NET Core Jwt 策略授权认证
[转]三分钟学会.NET Core Jwt 策略授权认证 一.前言# 大家好我又回来了,前几天讲过一个关于Jwt的身份验证最简单的案例,但是功能还是不够强大,不适用于真正的项目,是的,在真正面对复杂而 ...
- 中小研发团队架构实践之生产环境诊断工具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如同医生的听诊器,是系统生病时做问题诊断的逆向分析工具 ...
- 三分钟学会Redis在.NET Core中做缓存中间件
大家好,今天给大家说明如何在.NET Core中使用Redis,我们在想要辩论程序的好与坏,都想需要一个可视化工具,我经常使用的是一位国内大牛开发的免费工具,其Github地址为: https://g ...
- [计划任务 - Linux]三分钟学会cron
cron——计划任务,是任务在约定的时间执行已经计划好的工作,是一个linux下的定时执行工具,可以在无需人工干预的情况下运行作业. 也就是说cron只适合于linux系统,用windows电脑的同学 ...
- 三分钟学会funsioncharts
由于项目需求需要做一个报表,选择FusionCharts作为工具使用.由于以前没有接触过报表,网上也没有比较详细的fusionCharts教程,所以决定好好研究FusionCharts,同时做一个比较 ...
- 三分钟学会.NET微服务之Polly
熔断降级是一个非常重要的概念,我们先说一下什么是熔断降级,咱们都知道服务发现,一个有问题的服务器没来得急注销过一会就崩溃掉了,那么我们的请求就有可能访问一个已经崩溃的服务器,那么就会请求失败,因为已经 ...
- 小兔Java教程 - 三分钟学会Java文件上传
今天群里正好有人问起了Java文件上传的事情,本来这是Java里面的知识点,而我目前最主要的精力还是放在了JS的部分.不过反正也不麻烦,我就专门开一贴来聊聊Java文件上传的基本实现方法吧. 话不多说 ...
随机推荐
- uva 1482 - Playing With Stones
对于组合游戏的题: 首先把问题建模成NIM等经典的组合游戏模型: 然后打表找出,或者推出SG函数值: 最后再利用SG定理判断是否必胜必败状态: #include<cstdio> #defi ...
- php 文件上传 以及保存在本地的乱码问题处理
要知道两点: ①浏览器传到PHP程序中是UTF-8编码 ②PHP程序保存上传的文件,要转换成GBK编码才保存在本地中,否则如果直接使用浏览器传过来的文件名保存在本地,会出现文件名乱码. <?ph ...
- POJ_2446_Chessboard
题目意思就是一个M*N的有洞棋盘棋盘上,用1*2的板子去覆盖没有洞的地方,要求板子不能重叠,最终能否将棋盘完整覆盖. 代码: #include<stdio.h> #include<s ...
- ANDROID_MARS学习笔记_S02_015_Gson解析json串为对象集合
package com.example.s02_e12_json3; import java.lang.reflect.Type; import java.util.Iterator; import ...
- ppi和dpi
以下内容都是我自己总结的,如有不妥之处,请留言讨论,批评指正.万分感谢!ppi:可以用下面公式求得 对于手机屏幕来说,屏幕尺寸是固定的,分辨率一般是不可以调节的.所以ppi是一个定值.此值越高显示越细 ...
- BZOJ_3670_[NOI2014]_动物园_(kmp)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=3670 对于一个字符串,求出num数组,其中num[i]表示前i个字符构成的字串中不相重合的相同 ...
- Android Loader详解一:概述
装载器从android3.0开始引进.它使得在activity或fragment中异步加载数据变得简单.装载器具有如下特性: 它们对每个Activity和Fragment都有效. 他们提供了异步加载数 ...
- Google protobuf的安装及使用
最近应为工作的需要,合作的部门提供了protobuf的接口,总结了一下使用的过程和方法如下: 下载protobuf-2.3.0: http://protobuf.googlecode.com/file ...
- 获得WCF Client端的本地端口 z
当WCF调用远程服务时,显示该调用的网速或流量.其中比较关键的一步就是需要获得WCF Client端的本地端口,原来以为是个简单的事情,结果查了1个多小时谷歌,硬是没找到好的法子,只有自己动手了. ...
- Devexpress 之gridControl双击行事件
MouseDown事件 protected internal void gridControl1_MouseDown(object sender, MouseEventArgs e) { DevExp ...