实现三级缓存

博客转移到个人站点:
http://www.wangchengmeng.club/2018/02/04/%E5%AE%9E%E7%8E%B0%E4%B8%89%E7%BA%A7%E7%BC%93%E5%AD%98/

欢迎来吐槽

三级缓存

1.思想:

1.从网络上获取数据,效率比较低,速度较慢,而且需要联网

2.为了更高的提高读取已经从网络上获取过的数据,并且在没联网的情况下也可以浏览,在第一次从网络上获取数据的时候将数据存储到缓存文件中

3.为了提高读取效率,直接从内存中读取是最快的,可以将获取的数据保存到内存中(LruCache),在内存足够的情况下,系统直接从内存中读取数据,效率是比较高的,当然,当内存不足的时候,系统会回收你在内存中保存在数据,这个时候你就需要从缓存文件中读取,如果缓存文件没有的情况下,你再从网络上获取。

2.优点

1.对于读取你已经从网络上读取过的数据,使用三级缓存,可以大大提高读取数据的效率,

2.在没有联网的情况下你仍可以读取你保存的数据

3.不必每次都需要从网络上去获取数据,只是第一次访问的时候需要访问网络,节省了流量

3.实现一个三级缓存图片的工具类

1.定义一个工具类  BitmapCacheUtils并实现其构造方法

    public class BitmapCacheUtils {
        private HomeActivity mContext;
        private LruCache<String, Bitmap> lruCache;
        private ExecutorService threadPool;

        HashMap<ImageView,String> hm = new HashMap<ImageView,String>();
        public BitmapCacheUtils(HomeActivity context) {
            this.mContext = context;
            int maxSize = (int) (Runtime.getRuntime().freeMemory() / 2);  //运行的可用内存的一半
            //线程池
            threadPool = Executors.newFixedThreadPool(3);

            //1级缓存的容器   软引用
            //参数是你允许的最大缓存,你存储的数据不可以超过这个值,
            lruCache = new LruCache<String, Bitmap>(maxSize){
                @Override
                protected int sizeOf(String key, Bitmap value) {

                    //动态计算每张图片的大小
                    return value.getRowBytes() * value.getHeight();
                }

            };
        }


2.定义一个方法(根据传入的url给ImageView添加图片)

    public void display(ImageView image, String url) {

        // 首先从内存获取数据  内存有数据了 就不必去本地或者网络中获取了,提高效率
        Bitmap bitmap = lruCache.get(url);
        if(bitmap != null){
            image.setImageBitmap(bitmap);
            return;
        }

        // 从本地缓存文件中获取数据   
        Bitmap bitmap2 = getBitmapFromCache(url);   ---》3.
        if(bitmap2 != null){
            //本地有数据了,就直接本地获取,不必去网络中获取了
            image.setImageBitmap(bitmap2);
            return ;
        }

        //获取之前先将url存储在hashMap中
        hm.put(image, url);

        // 从网络获取数据
        getDataFromNet(image, url); ---》4.
    }

3.从本地读取图片的时候,如果读取有数据,也将其保存到内存中

    private Bitmap getBitmapFromCache(String url){
        //http://www.baidu.com/mm.png  url类似这钟,/在文件中是会影响到路径的读取,所以截取最后一个/后面的字符作为文件名
        File file = new File(mContext.getCacheDir(),url.substring(url.lastIndexOf("/") + 1));
        Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());

        if(bitmap != null){
            //如果本地有文件  在内存中保存一份
            lruCache.put(url, bitmap);
        }

        return bitmap;
    }

4.从网络中读取数据(耗时操作放在子线程中执行)

    private void getDataFromNet(ImageView image, String url) {

        //线程池提交任务  使用线程池 提高效率
        threadPool.submit(new Task(image,url));
    }

    //线程执行的任务类
    private class Task implements Runnable{
        public ImageView img;
        public String url;
        public Task(ImageView img ,String url){
            this.img = img;
            this.url = url;
        }
        @Override
        public void run() {
        getFromNet(img, url);  ---》5.
        }
    }

5.联网获取图片

    protected void getFromNet(final ImageView image, final String url) {

    try {
        URL cacheUrl = new URL(url);

        HttpURLConnection connection = (HttpURLConnection) cacheUrl
                .openConnection();
        connection.setConnectTimeout(5000);
        connection.setRequestMethod("GET");
        connection.connect();
        int code = connection.getResponseCode();
        if (code == 200) {
            // 请求成功
            InputStream is = connection.getInputStream();
            final Bitmap bitmap = BitmapFactory.decodeStream(is);

            // 往内存写入数据
            lruCache.put(url, bitmap);  ---》6.

            // 往本地写数据
            write2Local(bitmap, url);   ----》7.

            //子线程中不可以更新UI
            mContext.runOnUiThread(new Runnable() {

                @Override
                public void run() {

                    //在设置图片的时候,判断绑定的url是否是新的
                    if(hm.get(image).equals(url)){
                        //是新的url那就可以进行绑定了
                        image.setImageBitmap(bitmap);
                    }
                }
            });
        }

    } catch (Exception e) {
        e.printStackTrace();
    }

}


6.往内存中写入数据

    // 往内存写入数据
    lruCache.put(url, bitmap);

    主要是  LruCache这个类

    实例化:

            int maxSize = (int) (Runtime.getRuntime().freeMemory() / 2); //运行的可用内存的一半

            //1级缓存的容器   软引用
            //参数是你允许的最大缓存,你存储的数据不可以超过这个值,
            lruCache = new LruCache<String, Bitmap>(maxSize){
                @Override
                protected int sizeOf(String key, Bitmap value) {

                    //动态计算每张图片的大小
                    return value.getRowBytes() * value.getHeight();
                }

            };


7.往本地写入数据

    protected void write2Local(Bitmap bitmap, String url) {
        // 缓存文件
        File cacheDir = mContext.getCacheDir();
        File file = new File(cacheDir, url.substring(url.lastIndexOf("/") + 1));
        try {
            // 写入图片
            bitmap.compress(CompressFormat.PNG, 100,
                    new FileOutputStream(file));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }
    原文作者:xiaohuanqi
    原文地址: https://blog.csdn.net/xiaohuanqi/article/details/49208821
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞