DiskLruCache磁盘缓存

1.DiskLruCache的创建
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)使用此方法创建DiskLruCache,此方法共接收四个参数

第一个参数表示磁盘缓存在文件系统中的路径,具体为/sdcard/Android/data/package_name/cache目录,其中package_name为应用程序的包名,当应用程序被卸载后此目录会一并删除。
获取磁盘缓存在文件系统中的路径具体代码:

public File getDiskCacheDir(Context context,String uniqueName){
   String cachePath;
   //判断sd卡是否有读写权限,是否可被移除;当具有读写权限或者不可被移除,使用前者;否则使用后者                                                     
   if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageSt 
   ate())||!Environment.isExternalStorageRemovable(){
   //获取缓存路径;
       cachePath = context.getExternalCacheDir().getPath();
   }else {
       cachePath = context.getCacheDir().getPath();
   }
       return new File(cachePath+File.separator+uniqueName);
}

前者获取的路径为:/sdcard/Android/data/package_name/cache后者获取的路劲为: /data/data/package_name/cache,uniqueName为某一类型的数据的值,如图片类型可设置为bitmap,则最终获取的缓存路径为:/sdcard/Android/data/package_name/cache/bitmap

第二个参数为应用的版本号一般设置为1即可,当版本发生改变时会清空之前的缓存文件。

第三个参数为单个节点所对应的数据个数,设置为1即可,第四个参数表示缓存容器的总大小,如50MB,当需要缓存的文件超过该值时会自动清除部分缓存,从而保证缓存文件的大小不超过该缓存容器的大小。
创建一个open()可写为:

File cacheDir = getDiskCacheDir(context,"bitmap");
if(!cacheDir.exists()){
   //如果不存在,创建此文件夹
    cacheDir.mkdirs();
}
try{ 
    mDiskLruCache = DiskLruCache.open(cacheDir,1,1,50*1024*1024);
} catch (IOException e) {
    e.printStackTrace();
}

获取DiskLruCache实例后,接着就可以写入缓存
首先下载一张图片如http://img.my.csdn.NET/uploads/201309/01/1378037235_7476.jpg

private boolean downLoadUrlToStream(String url, final OutputStream outputStream){
   OkHttpClient mOkHttpClient = new OkHttpClient();
   Request request = new Request.Builder().url(url).build();
   BufferedInputStream in = null;
   BufferedOutputStream out = null;
   try {
      Response response = mOkHttpClient.newCall(request).execute();
      InputStream inputStream = response.body().byteStream();
      in = new BufferedInputStream(inputStream, 8 * 1024);
      out= new BufferedOutputStream(outputStream, 8 * 1024);
      int b;
      while ((b = in.read()) != -1) {
        out.write(b);
      }
        return true;
   }catch (IOException e) {
         e.printStackTrace();
   }finally {
       if(out!=null){
           try {
              out.close();
           } catch (IOException e) {
              e.printStackTrace();
           }
       }
       if (in!=null){
           try {
              in.close();
           } catch (IOException e) {
              e.printStackTrace();
           }
       }
   }
   return false;
}

DiskLruCache缓存的添加是通过Editor完成,然后将图片的url转化为key,根据key然后调用edit(String key),可以获取Editor对象,然后调用Editor对象的newOutputStream(int index)方法即可获取OutputStream对象,得到OutputStream对象和url后,使用上述downLoadUrlToStream(String url, final OutputStream outputStream),就可以将图片进行写入,但此时并没有写入文件系统还需调用Editor的commit()方法。

由于url中可能包含特殊字符,使其不能直接作为key,因此可使用MD5编码使其转化为key;

    public static String hashKeyForUrl(String url){
        String catchKey;
        try {
            final MessageDigest mDigest = MessageDigest.getInstance("MD5");
            mDigest.update(url.getBytes());
            catchKey = bytesToHexString(mDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            catchKey = String.valueOf(url.hashCode());
        }
        return catchKey;
     }
    private static 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();
    }

然后就可以获取Editor对像,并进行写入磁盘操作

     public void ImageLoading(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                String url = "https://img-my.csdn.net/uploads/201309/01/1378
                037235_7476.jpg";
                String key = hashKeyForUrl(url);
                try {
                    DiskLruCache.Editor editor = mDiskLruCache.edit(key);
                    if(editor!=null){
                        OutputStream outputStream = editor.newOutputStream(
                        0);
                        if(downLoadUrlToStream(url,outputStream)){
                            //进行写入操作
                            editor.commit();
                        }else {
                            //下载过程中出现异常退出操作
                            editor.abort();
                        }
                    }
                    //这个方法用于将内存中的操作记录同步到日志文件(也就是journal文
                    件)当中。
                    mDiskLruCache.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

读取缓存

缓存读取也需要将url转化为key,按照MD5上述编码方式转化即可。然后通过DiskLruCache的get(String key)方法获取Snapshot对象,接着通过Snapshot对象的getInputStream(int index)即可获取InputStream,然后就可以获取Bitmap对象。为了避免OOM需要对图片压缩后,再将其显示在ImageView上面。

Bitmap bitmap = null;
String url = "https://img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
String key = hashKeyForUrl(url);
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
if (snapshot != null) {
    FileInputStream fileInputStream = (FileInputStream) snapshot.getInputSt
    ream(0);
    //获取文件流对应的文件描述符
    FileDescriptor fileDescriptor = fileInputStream.getFD();
    //把图片压缩成100*100像素
    bitmap = decodeBitmapFromFileDescriptor(fileDescriptor, 100,100);
}

图片压缩

public static Bitmap decodeBitmapFromFileDescriptor(FileDescriptor fileDescriptor,int reqWidth,int reqHeight){
    final BitmapFactory.Options options = new BitmapFactory.Options();
    //inJustDecodeBounds 设置为true时BitmapFactory只会解析原始图片宽高,不会加载
    图片 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeFileDescriptor(fileDescriptor,null,options);                                         
    options.inSampleSize  = calculateInSampleSize(options,reqWidth,reqHeigh
    t);
    //当希望获取Bitmap实例时需要设置inJustDecodeBounds为false;
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFileDescriptor(fileDescriptor,null,options);
}

public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){
    //获取原始图片的宽高
    final int realWidth = options.outWidth;
    final int realHeight = options.outHeight;
    //定义采样率;
    int inSampleSize = 1;
    if(realHeight>reqHeight||realWidth>reqWidth){
       final int halfHeight = realHeight/2;
       final int halfWidth = realWidth/2;
       while ((halfHeight/inSampleSize)>=reqHeight&&(halfWidth/inSampleSize
       )>=reqWidth){
       inSampleSize*=2;
       }
    }
    return inSampleSize;
}

压缩图片时由于是FileInputStream方式,FileInputStream是一种有序的文件流,两次调用decodeStream影响了文件流的位置属性,导致第二次调用时返回null,为了解决此问题可以使用文件流对应的文件描述符,然后再进行加载。

Android DiskLruCache完全解析,硬盘缓存的最佳方案

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值