DiskLruCache磁盘缓存

来源:互联网 发布:wps表格查找重复数据 编辑:程序博客网 时间:2024/04/29 11:47

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 = "http://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 = "http://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完全解析,硬盘缓存的最佳方案

原创粉丝点击