图片缓存机制-DiskLruCache磁盘缓存

1、磁盘缓存 DiskLruCache

参考链接 https://blog.youkuaiyun.com/guolin_blog/article/details/28863651

记录总结:防止多图OOM的核心解决思路就是使用LruCache技术。但LruCache只是管理了内存中图片的存储与释放,如果图片从内存中被移除的话,那么又需要从网络上重新加载一次图片,这显然非常耗时。因此使用到了DiskLruCache进行硬盘/磁盘缓存

磁盘缓存的好处:在没有网络的情况下或者内存中被移除的情况下,依然可以快速加载图片。

DiskLruCache并没有限制数据的缓存位置,可以自由地进行设定,但是通常情况下多数应用程序都会将缓存的位置选择为 /sdcard/Android/data/<application package>/cache 这个路径。选择在这个位置有两点好处:第一,这是存储在SD卡上的,因此即使缓存再多的数据也不会对手机的内置存储空间有任何影响,只要SD卡空间足够就行。第二,这个路径被Android系统认定为应用程序的缓存路径,当程序被卸载的时候,这里的数据也会一起被清除掉,这样就不会出现删除程序之后手机上还有很多残留数据的问题。

创建DiskLruCache实例,需要调用的是open方法:

public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)

获取缓存地址的方法:

  1. public File getDiskCacheDir(Context context, String uniqueName) {  
  2.     String cachePath;  
  3.     if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())  
  4.             || !Environment.isExternalStorageRemovable()) {  
  5.         cachePath = context.getExternalCacheDir().getPath();  
  6.     } else {  
  7.         cachePath = context.getCacheDir().getPath();  
  8.     }  
  9.     return new File(cachePath + File.separator + uniqueName);  
  10. }  

因此,一个非常标准的open()方法就可以这样写:

[java]  view plain  copy
  1. DiskLruCache mDiskLruCache = null;  
  2. try {  
  3.     File cacheDir = getDiskCacheDir(context, "bitmap");  
  4.     if (!cacheDir.exists()) {  
  5.         cacheDir.mkdirs();  
  6.     }  
  7.     mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 110 * 1024 * 1024);  
  8. catch (IOException e) {  
  9.     e.printStackTrace();  
  10. }  

写入的操作:不能new对象,写入的操作是借助DiskLruCache.Editor这个类完成的。

public Editor edit(String key) throws IOException 

edit()方法接收一个参数key,这个key将会成为缓存文件的文件名,并且必须要和图片的URL是一一对应的。那么怎样才能让key和图片的URL能够一一对应呢?直接使用URL来作为key?不太合适,因为图片URL中可能包含一些特殊字符,这些字符有可能在命名文件时是不合法的。其实最简单的做法就是将图片的URL进行MD5编码,编码后的字符串肯定是唯一的,并且只会包含0-F这样的字符,完全符合文件的命名规则。

一次完整写入操作的代码如下所示:

[java]  view plain  copy
  1. new Thread(new Runnable() {  
  2.     @Override  
  3.     public void run() {  
  4.         try {  
  5.             String imageUrl = "https://img-my.youkuaiyun.com/uploads/201309/01/1378037235_7476.jpg";  
  6.             String key = hashKeyForDisk(imageUrl);  
  7.             DiskLruCache.Editor editor = mDiskLruCache.edit(key);  
  8.             if (editor != null) {  
  9.                 OutputStream outputStream = editor.newOutputStream(0);  
  10.                 if (downloadUrlToStream(imageUrl, outputStream)) {  
  11.                     editor.commit();  
  12.                 } else {  
  13.                     editor.abort();  
  14.                 }  
  15.             }  
  16.             mDiskLruCache.flush();  
  17.         } catch (IOException e) {  
  18.             e.printStackTrace();  
  19.         }  
  20.     }  
  21. }).start();  

注意在代码的最后我还调用了一下flush()方法,这个方法并不是每次写入都必须要调用的。一般在activity的onpause方法中调用。

读取缓存:读取的方法要比写入简单一些,主要是借助DiskLruCache的get()方法实现的

public synchronized Snapshot get(String key) throws IOException

读取缓存数据的代码就可以这样写:

[java]  view plain  copy
  1. String imageUrl = "https://img-my.youkuaiyun.com/uploads/201309/01/1378037235_7476.jpg";  
  2. String key = hashKeyForDisk(imageUrl);  
  3. DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key); 

这里获取到的是一个DiskLruCache.Snapshot对象,这个对象我们该怎么利用呢?很简单,只需要调用它的getInputStream()方法就可以得到缓存文件的输入流了。此时,即使在没有网络的情况下,也可以加载显示图片了。

移除缓存:DiskLruCache会根据我们在调用open()方法时设定的缓存最大值来自动删除多余的缓存。只有你确定某个key对应的缓存内容已经过期,需要从网络获取最新数据的时候才应该调用remove()方法来移除缓存。

DiskLruCache中使用了一个redundantOpCount变量来记录用户操作的次数,每执行一次写入、读取或移除缓存的操作,这个变量值都会加1,当变量值达到2000的时候就会触发重构journal的事件,这时会自动把journal中一些多余的、不必要的记录全部清除掉,保证journal文件的大小始终保持在一个合理的范围内。


用于类似图库,缓存,所困、缩略图 package com.example.cache; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.Map; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.util.DisplayMetrics; /** * 1.从内存中加载 * 2.本地缓存中加载 * 3.本地加载 * @author Administrator * */ public class LoadCacheImageTool { private Activity activity; private Map<String,SoftReference> cacheMap; public LoadCacheImageTool(Activity activity){ this.activity = activity; this.cacheMap = new HashMap<String, SoftReference>(); } public Bitmap loadCacheImage(String imagePath){ Bitmap bitmap = null; if (cacheMap.containsKey(imagePath)) { bitmap = cacheMap.get(imagePath).get(); if (bitmap!=null) { return bitmap; } } bitmap = loadLocalCacheImage(imagePath); cacheMap.put(imagePath, new SoftReference(bitmap)); return bitmap; } ///mnt/sdcard/bk.png ///mnt/sdcard/cache/bk.png.cache private Bitmap loadLocalCacheImage(String imagePath) { Bitmap bitmap = null; String cacheImagePath = getCacheImagePath(imagePath); File cacheFile = new File(cacheImagePath); if (!cacheFile.exists()) { bitmap = loadLocalBigImage(imagePath); saveToCacheDir(bitmap,cacheImagePath); }else{ try { bitmap = BitmapFactory.decodeStream(new FileInputStream(cacheFile)); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return bitmap; } private String getCacheImagePath(String imagePath) { String cacheDir = new File(imagePath).getParent()+"/cache/"; if (!new File(cacheDir).exists()) { new File(cacheDir).mkdirs(); } String newImageName = new File(imagePath).getName()+".cache"; String newImagePath = cacheDir+newImageNam
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值