Android使用磁盘缓存DiskLruCache
DiskLruCache 不同于LruCache,LruCache是将数据缓存到内存中去,而DiskLruCache是外部缓存,例如可以将网络下载的图片永久的缓存到手机外部存储中去,并可以将缓存数据取出来使用,DiskLruCache不是google官方所写,但是得到了官方推荐,DiskLruCache没有编写到SDK中去,如需使用可直接copy这个类到项目中去。
DiskLruCache地址: https://android.googlesource.com/platform/libcore/+/android-4.1.1_r1/luni/src/main/java/libcore/io/DiskLruCache.java
或者可以在Jake大神的Github上找到: https://github.com/JakeWharton/DiskLruCache
- ######DiskLruCache常用方法:
方法 | 备注 |
---|---|
DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) | 打开一个缓存目录,如果没有则首先创建它,**directory:**指定数据缓存地址 **appVersion:**APP版本号,当版本号改变时,缓存数据会被清除 **valueCount:**同一个key可以对应多少文件 **maxSize:**最大可以缓存的数据量 |
Editor edit(String key) | 通过key可以获得一个DiskLruCache.Editor,通过Editor可以得到一个输出流,进而缓存到本地存储上 |
void flush() | 强制缓冲文件保存到文件系统 |
Snapshot get(String key) | 通过key值来获得一个Snapshot,如果Snapshot存在,则移动到LRU队列的头部来,通过Snapshot可以得到一个输入流InputStream |
long size() | 缓存数据的大小,单位是byte |
boolean remove(String key) | 根据key值来删除对应的数据,如果该数据正在被编辑,则不能删除 |
void delete() | 关闭缓存并且删除目录下所有的缓存数据,即使有的数据不是由DiskLruCache 缓存到本目录的 |
void close() | 关闭DiskLruCache,缓存数据会保留在外存中 |
boolean isClosed() | 判断DiskLruCache是否关闭,返回true表示已关闭 |
File getDirectory() | 缓存数据的目录 |
- ######如何使用DiskLruCache:
1、因为要操作外部存储,所以必须要先加上权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
复制代码
另外要从网络下载图片,还要加上权限:
<uses-permission android:name="android.permission.INTERNET" />
复制代码
2、DiskLruCache是在外部存储上(如SD卡),所以首先判断外部存储是否存在:
/*** Get a usable cache directory (external if available, internal otherwise).* external:如:/storage/emulated/0/Android/data/package_name/cache* internal 如:/data/data/package_name/cache** @param context The context to use* @param uniqueName A unique directory name to append to the cache dir* @return The cache dir*/public static File getDiskCacheDir(Context context, String uniqueName) {final String cachePath = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||!isExternalStorageRemovable() ? context.getExternalCacheDir().getPath(): context.getCacheDir().getPath();return new File(cachePath + File.separator + uniqueName);}
复制代码
(1)、首先判断外部缓存是否被移除或已存满,如果已存满或者外存储被移除,则缓存目录=context.getCacheDir().getPath(),即存到 /data/data/package_name/cache 这个文件系统目录下; (2)、反之缓存目录=context.getExternalCacheDir().getPath(),即存到 /storage/emulated/0/Android/data/package_name/cache 这个外部存储目录中,PS:外部存储可以分为两种:一种如上面这种路径 (/storage/emulated/0/Android/data/package_name/cache), 当应用卸载后,存储数据也会被删除,另外一种是永久存储,即使应用被卸载,存储的数据依然存在,存储路径如:/storage/emulated/0/mDiskCache,可以通过Environment.getExternalStorageDirectory().getAbsolutePath() + "/mDiskCache" 来获得路径。
3、根据URL下载一个在线图片并把它写到输出流outputstream中:
/*** Download a bitmap from a URL and write the content to an output stream.** @param urlString The URL to fetch* @return true if successful, false otherwise*/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(), IO_BUFFER_SIZE);out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);int b;while ((b = in.read()) != -1) {out.write(b);}return true;} catch (Exception e) {Log.e(TAG, "Error in downloadBitmap - " + e);} finally {if (urlConnection != null) {urlConnection.disconnect();}try {if (out != null) {out.close();}if (in != null) {in.close();}} catch (final IOException e) {}}return false;}
复制代码
4、上面已经下载了图片,接着初始化DiskLruCache,并使用DiskLruCache.Editor准备缓存:
private static final int MAX_SIZE = 10 * 1024 * 1024;//10MBprivate DiskLruCache diskLruCache;private void initDiskLruCache() {if (diskLruCache == null || diskLruCache.isClosed()) {try {File cacheDir = CacheUtil.getDiskCacheDir(this, "CacheDir");if (!cacheDir.exists()) {cacheDir.mkdirs();}//初始化DiskLruCachediskLruCache = DiskLruCache.open(cacheDir, 1, 1, MAX_SIZE);} catch (IOException e) {e.printStackTrace();}}}
复制代码
下载图片时需要放在异步线程里,这里放在了AsyncTask的doInBackground中:
@Override
protected Boolean doInBackground(Object... params) {try {String key = Util.hashKeyForDisk(Util.IMG_URL);DiskLruCache diskLruCache = (DiskLruCache) params[0];//得到DiskLruCache.EditorDiskLruCache.Editor editor = diskLruCache.edit(key);if (editor != null) {OutputStream outputStream = editor.newOutputStream(0);if (downloadUrlToStream(Util.IMG_URL, outputStream)) {publishProgress("");//写入缓存editor.commit();} else {//写入失败editor.abort();}}diskLruCache.flush();} catch (IOException e) {e.printStackTrace();return false;}return true;
}
复制代码
上面代码中有个hashKeyForDisk()方法,其作用是把图片URL经过MD5加密生成唯一的key值,避免了URL中可能含有非法字符问题,hashKeyForDisk()代码如下:
/*** A hashing method that changes a string (like a URL) into a hash suitable for using as a* disk filename.*/public static 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 static String bytesToHexString(byte[] bytes) {// http://stackoverflow.com/questions/332079StringBuilder 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();}
复制代码
经过上面的代码,我们已经可以看到图片已经缓存到 /storage/emulated/0/Android/data/package_name/cache/CacheDir 这个目录下了:
第一个标识为110.78kb大小的就是我们缓存下来的图片,它的名字正是由图片的URL经过MD5加密得到的,它下面的journal文件是用来记录的,来看里面的内容:
第一行:libcore.io.DiskLruCache固定写死 第二行:DiskLruCache版本号 第三行:APP版本号,由open()方法的参数appVersion传入 第四行:同一个key可以对应多少文件,由open()方法的参数valueCount传入,一般为1 第五行:空格 第六行:以DIRTY开头,后面跟着的是图片的key值,表示准备缓存这张图片,当调用DiskLruCache的edit()时就会生成这行记录 第七行: 以CLEAN开头,后面跟着的是图片的Key值和大小,当调用editor.commit()时会生成这条记录,表示缓存成功;如果调用editor.abort()表示缓存失败,则会生成REMOVE开头的表示删除这条数据。
5、通过diskLruCache.get(key)得到DiskLruCache.Snapshot,key是经过MD5加密后那个唯一的key,接着使用Snapshot.getInputStream()可以得到输入流InputStream ,进而得到缓存图片:
private Bitmap getCache() {try {String key = Util.hashKeyForDisk(Util.IMG_URL);DiskLruCache.Snapshot snapshot = diskLruCache.get(key);if (snapshot != null) {InputStream in = snapshot.getInputStream(0);return BitmapFactory.decodeStream(in);}} catch (IOException e) {e.printStackTrace();}return null;}
复制代码
Bitmap bitmap = getCache();if (bitmap != null) {iv_img.setImageBitmap(bitmap);}
复制代码
效果图:
完整Demo地址: http://download.csdn.net/detail/u013700502/9883037
转载于:https://juejin.im/post/5a33e7ba51882540062688b5
Android使用磁盘缓存DiskLruCache相关推荐
- android强制缓存写磁盘,优雅的构建 Android 项目之磁盘缓存(DiskLruCache)
Android 的缓存技术 一个优秀的应用首先它的用户体验是优秀的,在 Android 应用中恰当的使用缓存技术不仅可以缓解服务器压力还可以优化用户的使用体验,减少用户流量的使用.在 Android ...
- android强制缓存写磁盘,Android缓存之DiskLruCache磁盘缓存的使用
DiskLruCache和LruCache不同的是,LruCache是内存缓存,而DiskLruCache是指磁盘缓存,顾名思义就是把文件缓存到磁盘,也也就是手机的内存卡中.接下来先简单介绍DiskL ...
- 具体解说Android的图片下载框架UniversialImageLoader之磁盘缓存(一)
沉浸在Android的开发世界中有一些年头的猴子们,预计都可以深深的体会到Android中的图片下载.展示.缓存一直是心中抹不去的痛.鄙人亦是如此.Ok,闲话不说.为了督促自己的学习.以下就逐一的挖掘 ...
- LruCache和DiskLruCache内存和磁盘缓存
客户端采用LRUCache和DiskLRUCache数据结构分别保存至内存和磁盘 知识点: 1.内存cache,应用杀进程后cache会被清楚:备注杀进程的adb命令:adb shell am fo ...
- Android/Linux 磁盘写入缓存/等待时间 参数修改
Linux系统当进行文件写操作时,并不会将数据立马写入磁盘,而是写写到缓存,等待达到占用内存一定比例或超过一定时间才会批量将这些缓存数据写入磁盘,这样可以减少IO操作,提升性能和磁盘寿命.如果数据还没 ...
- android glide设置缓存大小,Glide4-入门教程-5-缓存机制(内存缓存和磁盘缓存)
一.简介 这一节,主要是讲glide4的缓存机制.Glide的缓存设计是非常的先进的,考虑的场景也很周全.Glide 的缓存分为两种,一是内存缓存,另一个是硬盘缓存. 这两种缓存的作用各不相同,内存缓 ...
- Android Glide图片加载-缓存机制(内存缓存和磁盘缓存)
前言 glide的缓存机制.Glide的缓存设计是非常的先进的,考虑的场景也很周全.Glide 的缓存分为两种,一是内存缓存,另一个是硬盘缓存. 这两种缓存的作用各不相同,内存缓存的主要作用是防止应用 ...
- LruDiskCache要点--不可不用的磁盘缓存工具类
LruDiskCache是使用Lru算法的磁盘缓存类,它的功能是将LruCache中缓存位置由内存改为磁盘,一般两者结合使用,用于对处理小文件,图片的缓存. 下面记录下阅读过程中几个比较重要的点: G ...
- Android的图片缓存ImageCache(转)
为什么要做缓存? 在UI界面加载一张图片时很简单,然而如果需要加载多张较大的图像,事情就会变得更加复杂.在许多情况下(如ListView.GridView或ViewPager等的组件),屏 ...
最新文章
- Grafana 6.1.3 发布,系统指标监控与分析平台
- Spring cloud Loadbalance
- 【latex】输入角度符号°
- 中兴的芯片,到底什么水平?
- CvvImage.h和CvvImage.cpp
- 通过谓词查找第一个元素
- CentOS 6.3 上网慢问题
- Python -day 7
- STM8(STM8S003F3) Bootloader (IAP) 升级程序
- c++学习笔记:黑客攻击系统-功能菜单
- 微信表情包小程序源码
- 全新小说安装教程小程序源码
- PHPmywind 调用方法
- 软考初级信息处理技术员基础知识考点(建议收藏)
- 云函数.批量操作数据库
- 小程序添加好友的实现
- remoting项目运用
- 个人前端一些常用的网站
- Unity出现 error building player exception android (invocation failed)
- 线性同余法产生随机数C语言,线性同余生成随机数的一点思考