android lru缓存 辅助类LruCache 使用和解析

有一段日子没有写博客了,放假的时候事情挺多的,最近又在啃android,以前写listview,或者其他图片显示过大总会发生oom的错误,找了点时间去看了android对于LruCache的支持,记录一下。

  • LruCache 缓存到底是什么,LRU是Least Recently Used 的缩写,翻译过来就是“最近最少使用”,LRU缓存就是使用这种原理实现,简单的说就是缓存一定量的数据,当超过设定的阈值时就把一些过期的数据删除掉,比如我们缓存100M的数据,当总数据小于100M时可以随意添加,当超过100M时就需要把新的数据添加进来,同时要把过期数据删除,以确保我们最大缓存100M。
  • 听了lrucache的作用,是不是很适合作为一种内存管理的方法呢

构造方法

 /**     * @param maxSize for caches that do not override {@link #sizeOf}, this is     *     the maximum number of entries in the cache. For all other caches,     *     this is the maximum sum of the sizes of the entries in this cache.     */    public LruCache(int maxSize) {        if (maxSize <= 0) {            throw new IllegalArgumentException("maxSize <= 0");        }        this.maxSize = maxSize;          //传入具体的大小        this.map = new LinkedHashMap(0, 0.75f, true);  //通过将LinkedHashMap的accessOrder设置为true,将自动的实现lru缓存,即通过访问的顺序进行排序    }

可以看到构造方法中设置了最大的size同时创建了一个LinkedHashMap。

put方法

/**     * Caches {@code value} for {@code key}. The value is moved to the head of     * the queue.     *     * @return the previous value mapped by {@code key}.     */    public final V put(K key, V value) {        if (key == null || value == null) {                 //不允许添加null的key或者value            throw new NullPointerException("key == null || value == null");        }        V previous;        synchronized (this) {            putCount++;                       //将put的值加一            size += safeSizeOf(key, value);   //safeSizeOf()是一个用来计算大小的函数,这里默认返回1            previous = map.put(key, value);   //尝试将这个entry添加到map中            if (previous != null) {           //只有在替换了原有的entry的时候,才会返回不为null,这个时候我们需要对其进行size的复原                size -= safeSizeOf(key, previous);   //重新计算size,同时对其进行修正            }        }        if (previous != null) {             // 既然map中的值更新了,这个时候缓存中的值也需要更新,这个是一个空方法                    entryRemoved(false, key, previous, value);        }        trimToSize(maxSize);                       return previous;    }

get方法

这里提供了一个通用的方法,当没有找到对应的key的entry的时候,提供了一个默认返回null的creat方法(同样可以通过重写该方法让creat可以创建具体的对象)

public final V get(K key) {        if (key == null) {            throw new NullPointerException("key == null");        }        V mapValue;        synchronized (this) {            mapValue = map.get(key);            if (mapValue != null) {                hitCount++;                return mapValue;     //如果已经找到具体的对象,可以进行返回了            }            missCount++;        }        /*         * Attempt to create a value. This may take a long time, and the map         * may be different when create() returns. If a conflicting value was         * added to the map while create() was working, we leave that value in         * the map and release the created value.         */        V createdValue = create(key);        //如果没有找到,提供一种creat方法        if (createdValue == null) {          //为空直接返回null            return null;        }        synchronized (this) {            createCount++;            mapValue = map.put(key, createdValue);      //创建了就要添加到map进去,尝试添加            if (mapValue != null) {                     //同样只有在替换掉entry时候才不会返回null                // There was a conflict so undo that last put                map.put(key, mapValue);                //将mapValue添加            } else {                size += safeSizeOf(key, createdValue);    //已经将createdValue添加进去了,所以需要进行size添加            }        }        if (mapValue != null) {                                    entryRemoved(false, key, createdValue, mapValue);            return mapValue;        } else {            trimToSize(maxSize);                      //对size容量的检查,慢了就进行remove操作            return createdValue;        }    }

可以看到get方法传入了key进行查找,如果找到就返回,同时默认返回空的creat方法,当creat被重写后,creat可能会耗时,同时createdValue可能会改变,同时可能会有put方法将新的同样的key的方法添加进去,所以后面会看到和put方法一样的操作。

trimToSize方法 一个size 检查的函数,如果超过了 maxsize,则进行remove操作

public void trimToSize(int maxSize) {        while (true) {               //一个while循环            K key;            V value;            synchronized (this) {                if (size < 0 || (map.isEmpty() && size != 0)) {   //如果size小于0,或者map是空的(你还检查个鸡毛呀,抛异常)                    throw new IllegalStateException(getClass().getName()                            + ".sizeOf() is reporting inconsistent results!");                }                if (size <= maxSize || map.isEmpty()) {                    break;                                   //如果空间还足够                  }                Map.Entry toEvict = map.entrySet().iterator().next();   //如果不够了,不好意思。获取站在第一位的家伙,踢出去,谁叫你当出头鸟。                key = toEvict.getKey();                value = toEvict.getValue();                map.remove(key);                size -= safeSizeOf(key, value);             //移除掉的同时记得释放空间                evictionCount++;            }            entryRemoved(true, key, value, null);          //同样的进行entryRemoved操作              }    }

同时trimToSize方法将会对溢出情况进行判断,移除最少使用的部分。

更多相关文章

  1. Android中几种图像特效处理方法小结
  2. android 笔记 --- Android界面刷新的方法
  3. Android(安卓)数据库SQLite的使用简单Demo
  4. ArcGIS for Android安装配置详解
  5. android完全退出程序
  6. Android(安卓)APK应用安装原理(1)-解析AndroidManifest原理-Pack
  7. Android(安卓)ButterKnife框架的使用方法
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. Android之父安迪·鲁宾:极客文化的代表
  2. Android中屏幕密度和图片大小的关系分析
  3. GridView的属性
  4. Android基础知识总结
  5. Android(安卓)Bundle类别
  6. Android输入框弹出是否挤压页面的问题
  7. 修改 Android(安卓)开机 LOGO
  8. android system setup and building (3)
  9. Android实现文件上传功能(接收端用strust2
  10. Android(安卓)Studio中与网站通信