Android图片框架Picasso LRU缓存详解_Ubuntu_青云站长教程网
欢迎来到站长教程网!
  • 秒到短信接口 免费试用
  • 微信支付宝接口 秒结算
  • 中文网站排名|申请加入
  • 搜索引擎全站查询
  • 查询移动网站权重数据
  • 海外主机 台湾公司直销
  • Ubuntu

    当前位置:主页 > 服务器教程 > Ubuntu >

    Android图片框架Picasso LRU缓存详解

    时间:2019-09-11|栏目:Ubuntu|点击:
  • Picasso这个图片框架默认实现了内存中的LRU缓存,但是没有默认实现磁盘缓存(关于磁盘缓存的配置可以看我之前写的一篇博客),我在使用Picasso替换原来的xUtils框架的时候发现内存开销要比之前高好多,于是着手分析Picasso的LRU缓存策略,代码比较好读,下面简单的分析一下。

    Picasso加载一个图片的流程一般是这样的:

    url->检查LRU缓存中有没有对应的bitmap->调用HTTP框架准备下载该图片资源->http框架检查有没有磁盘缓存->http框架访问网络下载数据并进行缓存

    这里面的动作主要是由一个叫BitmapHunter的类完成的。

    Picasso有一个接口叫Cache,有一个实现叫LruCache,这个实现类里面是用一个LinkedHashMap<String, Bitmap>来进行缓存,key是图片url,value是bitmap,并不是其他框架爱用的WeakReference方案。

    这个实现类里面有几个控制内存使用量的成员,如下:

    private final int maxSize;//最大堆内存占用,单位字节
      private int size;//当前已经缓存到堆内存中所有bitmap所占的字节数
      private int putCount;//将bitmap存入LRU缓存的总次数
      private int evictionCount;//因为内存不足而将bitmap移出LRU缓存的总次数
      private int hitCount;//从LRU缓存中读取bitmap的总次数
      private int missCount;//没有从LRU缓存中根据url找到相应的bitmap的总次数

    来看一下添加一个bitmap到缓存的代码

    @Override public void set(String key, Bitmap bitmap) {
        if (key == null || bitmap == null) {
          throw new NullPointerException("key == null || bitmap == null");
        }

    Bitmap previous;
        synchronized (this) {//每次只能读写一个bitmap,因为LinkedHashMap是非线程安全的
          putCount++;//存bitmap计数器加一
          size += Utils.getBitmapBytes(bitmap);//获取一个bitmap所占内存的字节数
          previous = map.put(key, bitmap);//将bitmap存入到hashmap中去,以url为key,如果previous为空说明之前没有存储过该url,否则之前存储过
          if (previous != null) {//如果之前已经存储过这个url了
            size -= Utils.getBitmapBytes(previous);
          }
        }
    <span> </span>
        trimToSize(maxSize);//看看内存占用是否过大,如果太大的话就从LRU缓存中移出一部分bitmap
      }
    最重要的方法就是这个trimToSize(),它是用来回收bitmap缓存的,让我们来着重研究一下


    private void trimToSize(int maxSize) {
        while (true) {//一直执行销毁动作,直到当前占用的内存字节数小于规定的最大占用量
          String key;
          Bitmap value;
          synchronized (this) {//由于LinkedHashMap线程非安全,并且只有逐个释放才能准确比较剩余LRU大小,所以要同步执行
            if (size < 0 || (map.isEmpty() && size != 0)) {
              throw new IllegalStateException(
                  getClass().getName() + ".sizeOf() is reporting inconsistent results!");
            }

    if (size <= maxSize || map.isEmpty()) {
              break;
            }
    <span> </span>//LinkedHashMap可以看作是一个先入先出的栈,回收内存的时候先从栈底开始回收,也就是回收好久没用过的bitmap
            Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();
            key = toEvict.getKey();
            value = toEvict.getValue();
            map.remove(key);//将bitmap移出LRU缓存
            size -= Utils.getBitmapBytes(value);//将当前总堆内存占用量计数器减去移出的bitmap大小
            evictionCount++;//回收计数器加一
          }
        }
      }
    这个LRU缓存的最核心方法就这样分析完了,其实原理很简单,就是每放一个bitmap进LRU缓存都会记一下这个bitmap的大小,并计算当前LRU的总大小,如果发现总大小太大,就从栈底一个一个的把长时间没用的bitmap给回收掉

    那么Picasso如何规定最大内存占用量的呢,让我们来看代码


    /** Create a cache using an appropriate portion of the available RAM as the maximum size. */
      public LruCache(Context context) {
        this(Utils.calculateMemoryCacheSize(context));
      }这个LRU缓存类在构造的时候就规定了最大内存占用指标,关键就是这个Utils.calculateMemoryCacheSize()方法,我们来看看它是怎么规定的

    上一篇:Java守护线程的理解笔记

    栏    目:Ubuntu

    下一篇:Android Picasso加载webp格式图片节省流量

    本文标题:Android图片框架Picasso LRU缓存详解

    本文地址:http://www.jh-floor.com/fuwuqijiaocheng/Ubuntu/50153.html

    您可能感兴趣的文章

    广告投放 | 联系我们 | 版权申明

    重要申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

    如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

    联系QQ:888888 | 邮箱:888888#qq.com(#换成@)

    Copyright © 2002-2017 青云站长教程网 版权所有 琼ICP备xxxxxxxx号