DiskLruCache使用

DiskLruCache是Google官方提供的一种磁盘缓存的方案。如果用户每次获取图片都要从网上去获取,这将会非常耗费流量,而且效果也不太好,而DiskLruCache则很好地解决这个问题,只要下载一次,就将这张图片写入磁盘缓存,接下来每次从磁盘缓存中获取就可以了,省时省流量,可惜DiskLruCache暂时还没有写进SDK中,所以只能自己上网去下载源代码放进自己的项目中去。看看它是如何使用的:

创建DiskLruCache

DiskLruCache是不能通过new 创建实例化的,只能使用它提供的open方法来创建自身

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

这里有四个参数,分别的含义是磁盘缓存的文件,第二个参数是app的版本号,当版本号发生改变的时候,缓存就会被删除,所以一般设为1就可以了,第三个参数表示单个节点所对应的数据个数,一般设为1,第四个参数是缓存的大小。

注意:

  • 磁盘缓存文件这里,通常要判断一下文件夹是否存在,如果不存在,就要新建一个。通常都会自己写一个方法,来获取磁盘的缓存文件,当SD卡存在的情况,就存放在SD中
    public File getDiskCacheDir(Context context,String fileName){

        boolean externalStorageAvailable = Environment
                .getExternalStorageDirectory().equals(Environment.MEDIA_MOUNTED);
        //磁盘缓存的绝对路径
        final String cachePath;
        //当SD卡存在的情况下
        if (externalStorageAvailable){
            cachePath = context.getExternalCacheDir().getPath();
        }else{
            cachePath = context.getCacheDir().getPath();
        }

        return new File(cachePath + File.separator + fileName);
    }
  • 判断文件夹的大小是否满足所需的缓存大小,调用下列方法,就可以获取文件的可用空间大小
private long getUsableSpace(File path) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
            return path.getUsableSpace();
        }
        final StatFs stats = new StatFs(path.getPath());
        return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks();
    }

所以标准的一个创建缓存方法是:

File diskCacheFile = getDiskCacheDir(context,"diskLruCache");
        //如果文件不存在,则需要手动创建
        if (!diskCacheFile.exists()){
            diskCacheFile.mkdirs();
        }
        //当磁盘空间大于所需空间的时候,才能进行磁盘缓存
        if(getUsableSpace(diskCacheFile)>DISK_CACHE_SIZE){
            try {
                mDiskLruCache = DiskLruCache.open(diskCacheFile,1,1,DISK_CACHE_SIZE);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

写入缓存

DiskLruCache缓存添加时通过DiskLruCache.Editor来完成。首先,假如这里有一张图片的url=”http://img.my.csdn.net/uploads/201407/26/1406383242_3127.jpg”,我们首先要获取这个url的key值,这个key值我们一般是用url的md5,因为url里面可能存在一些特殊符号,而且md5值也是唯一的。

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

当得到这个key值的时候,就可以得到editor,并且根据这个editor就可以获得一个输出流
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
OutputStream out = editor.newOutputStream(0);
有了输出流之后,就可以当从网络下载图片的时候,图片就可以根据这个输出流写进文件系统。

private boolean downloadUriToStream(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 (IOException e) {
            e.printStackTrace();
        }finally {
            if (urlConnection != null){
                urlConnection.disconnect();
            }
            try {
                if (in != null){
                    in.close();
                }
                if (out != null){
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return  false;
    }

最后再通过editor.commit()来提交,最终的代码就是这样的:

/**
     * 写入缓存
     * @param uri
     */
    public void add2DiskLruCache(final String uri){
        new Thread(new Runnable() {
            @Override
            public void run() {
                //将uri的MD5作为key
                String key = hashKeyFormUrl(uri);
                try {
                    DiskLruCache.Editor editor = mDiskLruCache.edit(key);
                    if (editor != null){
                        OutputStream out = editor.newOutputStream(0);
                        if (downloadUriToStream(uri,out)){
                            editor.commit();
                        }else{
                            editor.abort();
                        }
                    }
                    mDiskLruCache.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

因为网络操作是一个耗时操作,不能将其放在主线程中运行,否则就会容易产生ANR。所以网络请求的操作需要在一个新的线程中执行。

读取缓存

获取缓存的话,就需要使用DiskLruCache.SnapShot这个对象。通过DiskLruCache.get(key)获取。当拿到这个对象之后,我们该怎样做呢?其实根据snapShot.getInputStream()就可以获取一个输入流,有了输入流之后,就简单多了,BitmapFactory.decodeStream(inputStream)就可以获取bitmap。

public Bitmap getDiskLruCache(String uri){
        String key = hashKeyFormUrl(uri);
        try {
            DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
            if (snapshot != null){
                InputStream inputStream = snapshot.getInputStream(0);
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                return bitmap;

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

这里写图片描述
这是根据《Android 开发艺术探索》所写的。

猜你喜欢

转载自blog.csdn.net/lihuanxing/article/details/52124540
今日推荐