文章参考:http://blog.csdn.net/guolin_blog/article/details/28863651
在此多谢作者分享,受益匪浅!!!
众所周知,LruCache技术是防止多图OOM的核心解决思路,但LruCache只是管理了内存中图片的存储与释放,如果图片从内存中被移除的话,那么又需要从网络上重新加载一次图片,这显然非常耗时。对此,Google又提供了一套硬盘缓存的解决方案:DiskLruCache(非Google官方编写,但获得官方认证)。
1,缓存位置:
DiskLruCache并没有限制数据的缓存位置,可以自由地进行设定,但是通常情况下多数应用程序都会将缓存的位置选择为 /sdcard/Android/data/<application package>/cache 这个路径。选择在这个位置有两点好处:第一,这是存储在SD卡上的,因此即使缓存再多的数据也不会对手机的内置存储空间有任何影响,只要SD卡空间足够就行。第二,这个路径被Android系统认定为应用程序的缓存路径,当程序被卸载的时候,这里的数据也会一起被清除掉,这样就不会出现删除程序之后手机上还有很多残留数据的问题。
路径下bitmap文件夹下,有一个名为journal的文件,journal文件是DiskLruCache的一个日志文件,程序对每张图片的操作记录都存放在这个文件中,基本上看到journal这个文件就标志着该程序使用DiskLruCache技术了。而bitmap中一堆文件名很长的文件就是缓存的图片。
2,代码使用:
(1)首先你要知道,DiskLruCache是不能new出实例的,如果我们要创建一个DiskLruCache的实例,则需要调用它的open()方法,接口如下所示:
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
第一个参数指定的是数据的缓存地址,第二个参数指定当前应用程序的版本号,第三个参数指定同一个key可以对应多少个缓存文件,基本都是传1,第四个参数指定最多可以缓存多少字节的数据。
为了防止SD正好被移除了的情况,我们写一个代码获取缓存地址:
public File getDiskCacheDir(Context context, String uniqueName) {
String cachePath;
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);
}
当SD卡存在或者SD卡不可被移除的时候,就调用getExternalCacheDir()方法来获取缓存路径,否则就调用getCacheDir()方法来获取缓存路径。前者获取到的就是 /sdcard/Android/data/<application package>/cache 这个路径,而后者获取到的是 /data/data/<application package>/cache 这个路径。uniqueName:缓存文件夹名。
获取应用版本号:
public int getAppVersion(Context context) {
try {
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return info.versionCode;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return 1;
}
说明:每当版本号改变,缓存路径下存储的所有数据都会被清除掉,因为DiskLruCache认为当应用程序有版本更新的时候,所有的数据都应该从网上重新获取。
so,open方法:
DiskLruCache mDiskLruCache = null;
try {
File cacheDir = getDiskCacheDir(context, "bitmap");
if (!cacheDir.exists()) {
cacheDir.mkdirs();
}
mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);
} catch (IOException e) {
e.printStackTrace();
}
首先调用getDiskCacheDir()方法获取到缓存地址的路径,然后判断一下该路径是否存在,如果不存在就创建一下。接着调用DiskLruCache的open()方法来创建实例,并把四个参数传入即可。
有了DiskLruCache的实例之后,我们就可以对缓存的数据进行操作了,操作类型主要包括写入、访问、移除等
(2)网络URL图片 写入本地缓存:
写入的操作是借助DiskLruCache.Editor这个类完成的。类似地,这个类也是不能new的,需要调用DiskLruCache的edit()方法来获取实例
public Editor edit(String key) throws IOException
key将会成为缓存文件的文件名,并且必须要和图片的URL是一一对应的,因为图片URL中可能包含一些特殊字符,这些字符有可能在命名文件时是不合法的。其实最简单的做法就是将图片的URL进行MD5编码,编码后的字符串肯定是唯一的,并且只会包含0-F这样的字符,完全符合文件的命名规则。
public String hashKeyForDisk(String key) {
String cacheKey;
try {
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(key.getBytes());
cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(key.hashCode());
}
return cacheKey;
}
private String bytesToHexString(byte[] bytes) {
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);
}
return sb.toString();
}
String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
String key = hashKeyForDisk(imageUrl);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
有了DiskLruCache.Editor的实例之后,我们可以调用它的newOutputStream()方法来创建一个输出流,然后把它传入到downloadUrlToStream()中就能实现下载并写入缓存的功能了。注意newOutputStream()方法接收一个index参数,由于前面在设置valueCount的时候指定的是1,所以这里index传0就可以了。在写入操作执行完之后,我们还需要调用一下commit()方法进行提交才能使写入生效,调用abort()方法的话则表示放弃此次写入。
new Thread(new Runnable() {
@Override
public void run() {
try {
String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
String key = hashKeyForDisk(imageUrl);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if (editor != null) {
OutputStream outputStream = editor.newOutputStream(0);
if (downloadUrlToStream(imageUrl, outputStream)) {
editor.commit();
} else {
editor.abort();
}
}
//这个方法并不是每次写入都必须要调用的,但在这里却不可缺少
mDiskLruCache.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
HttpURLConnection urlConnection = null;
BufferedOutputStream out = null;
BufferedInputStream in = null;
try {
final URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
out = new BufferedOutputStream(outputStream, 8 * 1024);
int b;
while ((b = in.read()) != -1) {
out.write(b);
}
return true;
} catch (final IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (final IOException e) {
e.printStackTrace();
}
}
return false;
}
(3)读取缓存:
public synchronized Snapshot get(String key) throws IOException
get()方法要求传入一个key来获取到相应的缓存数据,而这个key毫无疑问就是将图片URL进行MD5编码后的值了。
这里获取到的是一个DiskLruCache.Snapshot对象,调用它的getInputStream()方法就可以得到缓存文件的输入流,同样地,getInputStream()方法也需要传一个index参数,这里传入0就好。一段完整的读取缓存,并将图片加载到界面上的代码如下所示:
try {
String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
String key = hashKeyForDisk(imageUrl);
DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
if (snapShot != null) {
InputStream is = snapShot.getInputStream(0);
Bitmap bitmap = BitmapFactory.decodeStream(is);
mImage.setImageBitmap(bitmap);
}
} catch (IOException e) {
e.printStackTrace();
}
(4)移除缓存:
public synchronized boolean remove(String key) throws IOException
说明:这个方法我们并不应该经常去调用它。因为你完全不需要担心缓存的数据过多从而占用SD卡太多空间的问题,DiskLruCache会根据我们在调用open()方法时设定的缓存最大值来自动删除多余的缓存。只有你确定某个key对应的缓存内容已经过期,需要从网络获取最新数据的时候才应该调用remove()方法来移除缓存。
(5)其他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()方法就可以实现了。
分享到:
相关推荐
Android之本地缓存——LruCache(内存缓存)与DiskLruCache(硬盘缓存)统一框架 [注:本内容来自网络,在此分享仅为帮助有需要的网友,如果侵犯了您的权利,麻烦联系我,我会第一时间删除,谢谢您。]
本教程将深入探讨如何在Android应用中仿照今日头条实现新闻的缓存加载功能,以及如何利用DiskLruCache进行硬盘缓存的学习。 首先,我们需要理解缓存加载的基本概念。缓存是一种存储技术,用于暂时保存数据,以便在...
基于LruCache(内存缓存)和DiskLruCache(硬盘缓存)的图片三级缓存工具类是一种优化策略,它通过在内存和磁盘上建立缓存,实现了快速响应和减少网络请求,从而提升应用的运行效率。本文将详细介绍这两个缓存机制...
Android 磁盘缓存 DiskLruCache类 调用封装 缓存Bitmap String 相关的博客地址:http://blog.csdn.net/tangzhide/article/details/52489982
DiskLruCache是Android系统提供的一个基于硬盘的LRU(Least Recently Used)缓存实现,主要用于存储那些不适合在内存中长期驻留但又需要频繁访问的数据。本文将深入解析DiskLruCache的工作原理、使用方法以及与其他...
谷歌推荐磁盘缓存 DiskLruCache.java 缓存类 主要用于安卓图片磁盘缓存,放入项目中修改包名直接调用即可.
`DiskLruCache` 是一个在Android系统中广泛使用的磁盘缓存库,主要用于存储和检索大量的数据,以减少对网络请求的依赖,提高用户体验。这个"Android-一个封装DiskLruCache的缓存工具类"正是为了简化开发者使用`...
Android DiskLruCache,硬盘缓存的最佳方案,研究源代码吧!
DiskLruCache虽然功能强大,但在Android 4.0(API 14)之后,Google推荐使用`android.support.v4.util.LruCache`或`OkHttp`的内部缓存机制,它们提供了更高级别的抽象和更好的性能。 总之,通过DiskLruCache设置...
在Android开发中,DiskLruCache是一个非常重要的缓存机制,它基于磁盘,用于存储大量数据,以缓解内存压力并提高应用性能。这个压缩包包含的类是实现DiskLruCache功能的基础组件。以下是对这些类的详细解释: 1. `...
本文将详细探讨两种常用的Android缓存机制——LruCache和DiskLruCache。 首先,我们来了解内存缓存LruCache。LruCache全称为“Least Recently Used Cache”,即最近最少使用缓存策略。它是Android SDK提供的一种...
在Android开发中,DiskLruCache是一个非常重要的缓存机制,尤其在处理大量图片或大文件时,能够有效地提高应用性能并减少网络流量的消耗。本Demo主要展示了如何在Android项目中集成和使用DiskLruCache来缓存Bitmap...
"缓存-DiskLruCache+LruCache"这个主题涉及到的是Android系统中的两种常见缓存策略:内存缓存(LruCache)和硬盘缓存(DiskLruCache)。这两种缓存机制都是基于LRU(Least Recently Used)算法,它是一种常用的页面...
《DiskLruCache:Java实现的磁盘缓存解析》 在移动开发,尤其是Android应用开发中,数据缓存是优化用户体验的关键技术之一。DiskLruCache是一款基于磁盘的缓存库,由Jake Wharton编写,用于存储关键数据到本地文件...
本文将深入探讨两种常用的Android缓存技术:LruCache和DiskLruCache。 1. **LruCache(Least Recently Used Cache)**: LruCache是Android SDK中的一个基于LRU算法的内存缓存机制。LRU策略指的是当缓存满时,最近...
**DiskLruCache**是Android系统中用于实现磁盘缓存的一种机制,它基于LRU(Least Recently Used)算法,即最近最少使用算法。在Android应用开发中,内存缓存可能不足以存储所有需要快速访问的数据,这时就需要使用到...
标题中的“将固态作为机械硬盘缓存工具,类似Intel快速储存驱动”指的是利用固态硬盘(SSD)作为机械硬盘(HDD)的高速缓存,以提高整体存储系统的性能。这种技术与Intel的 Rapid Storage Technology (RST) 类似,...