DiskLruCache理解使用心得

DiskLruCache

本文的基础,都是建立在看了郭神的博客之后,如有从未接触过DiskLreCache技术的,课先看郭霖的文章,以上是地址。
http://blog.csdn.net/guolin_blog/article/details/28863651

接下来说到自己:

DiskLreCache是一个类似三级缓存技术,就是将文件图片或者是字符串,从网络获取到,存进SD卡中,再从SD卡中获取数据再显示到UI之上,优点在于不用担心app运行内存,只要SD的存储空间够就不会有问题,也不会影响程序,但是再好的代码,自己没有去写过用过,终究只是雾里看花。接下来是实操:

1.创建package libcore.io 包

这是固定模式,其次将DiskLruCache的Java代码全部CV过去就好,这样就成功导入了.

2.创建DiskLruCache对象,初始化


    /**
     * 初始化mDiskLruCache,给他赋值
     * 这一步不先进行,会空指针因为
     * getInfo方法会报空指针
     */
    private void init() {
        try {
            File cacheDir = getDiskCacheDir(MainActivity.this, "bitmap");
            if (!cacheDir.exists()) {
                cacheDir.mkdirs();
            }
            mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(MainActivity.this), 1, 10 * 1024 * 1024);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

该方法一定要最早用,这样之后的方法才不会有任何报空指针的错误,一定需要先创建DiskLruCache对象,且是通过open方法,并不是new出来的。

其中有一个方法getDiskCacheDir()来判断是否有SD卡,如果有再返回一个自己组装的路径。

 /**
     * 判断是否有SD卡来得到存储路径
     * 再在路径之后加上自己进行Android/data目录下的缓存路径
     * 返回新的SD卡缓存的路径
     *
     * @param context
     * @param uniqueName
     * @return
     */
    public File getDiskCacheDir(Context context, String uniqueName) {
        String cachePath;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                || !Environment.isExternalStorageRemovable()) {
            cachePath = context.getExternalCacheDir().getPath();
        } else {
            cachePath = context.getCacheDir().getPath();
        }
        return new File(cachePath + File.separator + uniqueName);
    }

上一步是检测是否有SD卡,还需要动态的获取app的版本号,因为DiskLruCache是默认的认为版本号如果不一致则删除所有缓存并联网拉取新的数据缓存。

 /**
     * 动态的获取到app版本号,优点在于灵活
     * 因为版本号不一致就会删除所有相关缓存
     *
     * @param context
     * @return
     */
    public int getAppVersion(Context context) {
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            return info.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return 1;
    }

3.获得图片,将图片写入到SD卡中

 /**
     * 写入缓存,通过联网读取图片,通过url保存输出流
     * 再将文件保存在bitmap文件夹下
     */
    private void getInfo() {


        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //如果当前线程是在主线程 则异常
                    if (Looper.myLooper() == Looper.getMainLooper()) {
                        Log.w("Tag", "load bitmap from UI Thread, it's not recommended!");
                        throw new RuntimeException("can not visit network from UI Thread.");
                    }
                    //设置key,并根据URL保存输出流的返回值决定是否提交至缓存
                    String imageUrl = "https://img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
                    String key = hashKeyForDisk(imageUrl);
                    DiskLruCache.Editor editor = mDiskLruCache.edit(key);
                    if (editor != null) {
                        OutputStream outputStream = editor.newOutputStream(0);
                        if (downloadUrlToStream(imageUrl, outputStream)) {
                            editor.commit();
                        } else {
                            editor.abort();
                        }
                    }
                    mDiskLruCache.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();


    }

该方法需要用于子线程,主线程就会报异常。其中还有个方法就是downloadUrlToStream(imageUrl, outputStream),继续来写这个方法,通过输出流得到图片。

/**
     * 将URL中的图片保存到输出流中
     *
     * @param urlString    图片的URL地址
     * @param outputStream 输出流
     * @return 输出流
     */
    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(), 8 * 1024);
            out = new BufferedOutputStream(outputStream, 8 * 1024);
            int b;
            while ((b = in.read()) != -1) {
                out.write(b);
            }
            return true;
        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

这个方法来得到需要下载的图片。

其实每一个url都是相对应的key,只是不方便直接用key来做名字,所以才进行一个MD5编码混淆,但是对于程序而言,他就自己能分辨,这个url的名字,MD5之后的名字对应哪一个图片。,也是类似key-value的关系吧
当然,我们会发现得到的图片都是一串看不懂的字符名,这是经过MD5编码过后的命名,所以还需要进行MD5编码:

 /**
     * 通过MD5编码,将图片的url编码成一串不规律字符
     *
     * @param key
     * @return
     */
    public 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;
    }

    /**
     * MD5编码中的方法,来生成随机字符串
     *
     * @param bytes
     * @return
     */
    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();
    }

到这里就已经完成将网络图片拉取缓存到自己手机的全部过程了!

4.将缓存的图片,读取到UI界面上

 /**
     * 读取缓存,将本地缓存的图片显示到页面上
     */
    private void showImageInfo() {
        try {
            String imageUrl = "https://img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
            String key = hashKeyForDisk(imageUrl);
            DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
            if (snapShot != null) {
                InputStream is = snapShot.getInputStream(0);
                Bitmap bitmap = BitmapFactory.decodeStream(is);
                img.setImageBitmap(bitmap);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

读取方法也很好理解。这样就是一个DiskLruCache缓存读取的全部过程。不光图片,我们还可以自己在自己命名的文件夹下创建文本记录下get.post得到的返回数据,再从这里进行读取照常解析都可以,只是图片的DiskLruCache看起来会更加实用。

注意:其实对于第一次用,多少还是没马上就理解,主要几个点。

第一,文件的路径,仔细看几遍,打开手机的文件管理去找就清楚了。

第二,DiskLruCache mDiskLruCache 的初始化,就是创建这个缓存文件,不然之后的操作很可能会造成空指针异常。

第三,getInfo()方法一定要在子线程,毕竟联网拉取图片的操作在这里,不新开线程,就只能等着报错了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值