LruCache报错IllegalStateException

描述

定义LruCache:

LruCache cache = new LruCache<String, List<?>>(maxSize){
	@Override
	protected int sizeOf(String key, List<?> value){
		return EmptyUtil.isEmpty(value) ? 1 : value.size();
	}
}

但是在清空缓存的调用cache.evictAll()的时候偶尔会报错,

new IllegalStateException(cache.sizeOf() is reporting inconsistent results!);

即 LruCache中自己维护的size 和实际存储数据map的size,无法对应。

原因:

我们缓存的list中数据存在可用行,我们偶尔会对list中数据进行清理,假如数据entry已经是不可用状态,将会移除这个数据。

        List<?> list = cache.get(key);
        if (!EmptyUtil.isEmpty(list) && list.size() > 1) {
            filterAndRemove(list);         
        }

也就是这段代码导致出了问题。

由于我们修改了list的size。导致我们在之后向cache中添加数据的时候计算错误。

  public final V put(K key, V value) {
        if (key == null || value == null) {
            throw new NullPointerException("key == null || value == null");
        }

        V previous;
        synchronized (this) {
            putCount++;
            size += safeSizeOf(key, value);
            previous = map.put(key, value);
            if (previous != null) {
                size -= safeSizeOf(key, previous);//这里出了问题
            }
        }

        if (previous != null) {
            entryRemoved(false, key, previous, value);
        }

        trimToSize(maxSize);
        return previous;
    }

当我们添加了相同key的数据到cache中时,由于我们修改了list的大小。导致

size -= safeSizeOf(key, previous);

size减去的值并不是list添加的时候的值。 导致了LruCache中的size出现问题。
eg:

List<?> a = new List<String>{};
List<?> b = new List<String>{};
for(int i=0; i<20; i++){
	a.add("value:" + i);
	b.add("value:" + i);
}
cache.put("key", a);  //这时候cache的值为20
a.remove(0);
//当再次添加key为‘key’的值的时候,LruCache计算size为
//size +=b.size(), size-=a.size();
//即size = 20 + 20, size = 40-19;
//从而导致size值为21,但是cache中存储的数据,为b的size 20个。
cache.put("key", b); 

当我们清除cache的时候,将value中数据都清除掉,但是size并不为0.从而报错。

解决

  1. 重写sizeOf(), 最大缓存数量使用list的数量,而不是list 的entry的数量。
  2. 在需要修改list的数量的时候,使用cache.remove(key)取出value而不是cache.get(key).
    然后修改完后再cache.put(key, value).
  3. 修改value值为包装类,cache的sizeOf使用A.getSize();
    这样LruCache获取的size 一直时添加的时候的值。
	class A {
		List<?> value;
		int size;

		public A(List<?> value){
			this.value = value;
			this.size = EmptyUtil.isEmpty(value)? 1 : value.size();
		}

		public int getSize(){
			return size;
		}
		public List<?> getValue(){
			return value;
		}
	}

你可能感兴趣的:(android开发报错)