三级缓存的理解

三级缓存图片

自己的第一篇小笔记,第一次完整的使用markdownpad进行文章的编辑,在某马学android也有快3个月了,一直都没有系统的总结自己说学过的知识点.所以这次下定决心用blog记录自己所学习的知识点,希望能激励自己,接下来也会将自己以前的知识点做个巩固,并做成笔记发到blog上,只有好好的巩固了知识点,以后才能找到满意的工作^ ^

三级缓存图片的概念

加载网络图片,比较耗时,因此每次去访问网络加载图片是非常消耗时间和流量的,因此对图片进行缓存是非常有必要的

三级缓存的优点

  • 优先从内存中加载图片, 速度最快, 不浪费流量
  • 其次从本地(sdcard)加载图片, 速度快, 不浪费流量
  • 最后从网络下载图片, 速度慢, 浪费流量

三级缓存的流程

  • 从内存中获取

    • 从sd卡中获取(如果从内存中没有缓存的话)

    • 如果从sd卡获取到了就保存一份到内存中

    • 没有获取到就去网络获取

  • 从网络去获取

    • 网络获取到后,保存一份到内存中,保存一份到sd卡中,以便下次读取的时候,可以不用去请求网络获取

代码实现

  • 将代码封装在一个方法中

    LoadUtils.getImage(String url);

    class LoadUtils {
        //LruCache是android v4包下提供的用来获取缓存的类,类似与一个map,有键值对
        private Context mContext;
        private LruCache<String, Bitmap> lruCache;
        private ExecutorService newFixedThreadPool;
        public LoadUtils(Context context) {
            //[0.1]我们知道每个app运行的堆内存(VM heap)最大是16M,当然有的可以是32M,不过最多的还是16M
            //Runtime是java提供的类,因为是单例的,获取他的实例,要用getRuntime.
            int maxSize = (int)(Runtime.getRuntime().maxMemory()/8);
            //[0]在构造方法中初始化LruCache,形式参数是LruCache可以维护的最大内存,是个int值
            lruCache = new LruCache<String, Bitmap>(maxSize) {
                //要重写里面的sizeOf()方法
                @override
                protected int sizeOf(String key, Bitmap bitmap) {
                    //在此处返回bitmap的大小,计数,为了不让lruCache内存溢出
                    //图片的大小就是图片的行像素*图片的高度
                    return  bitmap.getRowBytes()*bitmap.getHeight();
                }
            };
            //创建线程池,用于网络访问下载图片的时候,这个方法其实就是new了一个线程池
            newFixedThreadPool = Executors.newFixedThreadPool(5);
            this.mContext = context;
        }
    
    
        public Static Bitmap getImage(String url,RequestCallback callback) {
            //[1]先从内存中获取            
            Btimap bitmap = getImageFromCache(url);
            //判断bitmap是否为空
            if(bitmap != null) {
                return bitmap;
            }
    
            //[2]bitmap等于空,从磁盘上获取
            bitmap = getBitmapFromCacheFile(url);
            //判断获取的bitmap是否为空
            if(bitmap != null) {
    
                return bitmap;
            }
    
            //[3]如果从sd卡获取还是为空,就从网络去获取bitmap
            getImageFromNet(url,callback);
    
            return null;
        }
    
        //[1]先从内存中获取        
        private Bitmap getImageFromCache(String url) {
            //用lruCache获去bitmap
            Bitmap bitmap = lruCache.get(url);
            return bitmap;
        }
    
        //[2]从磁盘上获取
        private Bitmap getBitmapFromCacheFile(url) {
    
            try {
                //获去缓存文件夹,一般保存在磁盘的文件名称都与Md5加密过的
                String fileName = MD5Encoder.encode(imageUrl);
                //2.图片放到哪个文件夹下去存储(sd卡,files文件夹,cache文件)
                File file = new File(mCtx.getCacheDir(), fileName);
                //判断文件是否存在
                if(file == null || !file.exist()) {
                    return null;    
                }
                //3.从文件中获取图片
                Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
                //4.往内存中存储一份
                lruCache.put(imageUrl, bitmap);
                return bitmap;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        //[3]从网络获取图片
        private void getImageFromNet(String url,RequestCallback callback) {
            //从网络获取图片,因为获取图片是网络获取的,所以要在子线程中进行,但是下载图片的时候开启一个子线程的话,会开启很多,因此就要开启使用线程池
            newFixedThreadPool.exeucte(new RunnableTask(url,callback));
    
        }
    
        class RunnableTask implements Runnable {
            String imageUrl;
            RequestCallback mCallback;
            public RunnableTask(String url,callback) {
                imageUrl = url;
                this.mCallback = callback;
            }
            //开始请求网络获取图片
            @override
            public void run() {
    
                try {
                    //将url封装一下
                    URL url = new URL(imageUrl);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setConnectTimeout(3000);
                    connection.setReadTimeout(3000);
                    //如果响应码是200,说明返回成功
                    if(connection.getResponseCode() == 200){
                        InputStream inputStream = connection.getInputStream();
                        //输入流转换成图片
                        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                        //网络获取图片后,需要在内存中存储一份
                        lruCache.put(imageUrl, bitmap);
                        //文件中写入一份
                        saveToCache(bitmap);
                        //因为还在子线程,所以要自己转到主线程中
                        ((XXActivity)mContext).runOnUiThread(new Runnable() {
                                                    @Override
                                                    public void run() {
                                                        mCallback.downLoadFinished(bitmap);
                                                    }
                                                });
                        return;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        //[4]从网络获取后,保存一份到本地文件中
        //存储图片的方法
        private void saveToCache(Bitmap bitmap){
            try {
                String fileName = MD5Encoder.encode(imageUrl);
                //2.图片放到哪个文件夹下去存储(sd卡,files文件夹,cache文件)
                File file = new File(mContext.getCacheDir(), fileName);
                //3.往指定file写入数据
                FileOutputStream fileOutputStream = new FileOutputStream(file.getAbsolutePath());
                //4.写入文件
                //参数一:存储图片的个数
                //参数二:存储图片的质量,是否压缩
                //参数三:输出流对象
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
  • 以上就是初步的代码实现,还遗留一些小问题

    因为从网络下载图片是异步的,因此我们并不能确定什么时候可以获取到图片,这是可以用回调,等图片下载完的时候回调下载好的图片,也可以用hander,用message的方式传递bitmap图像.

    我们老师用的handler用来实现网上下载的图片的获取

    • 回调就是声明一个接口

      interface RequestCallback {
      void downLoadFinished(Bitmap bitmap);
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值