LruCache源码
在Android-27中查看LruCache源码(不要在Android-28中看,其中有些问题)
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
从构造函数中可以看出其内部的实现是LinkedHashMap并将LinkedHashMap中的accessOrder设置为true,accessOrder的作用参考文章:LinkedHashMap中的accessOrder - 简书
其中maxSize是在缓存中可以存放的最大数量,一般使用时结合sizeOf方法,sizeOf方法的默认实现如下:
protected int sizeOf(K key, V value) {
return 1;
}
可以结合项目需要看是否重写该方法。
在使用时常用的是put,get方法,下面我们来看看这两个方法的实现:
图1在图1的put方法中,我们可以看出其内部调用的是LinkedHashMap的put方法,如果key已经存在,就是相当于修改原有的值,则size保持不变,否则size加上sizeOf的返回值。其中LinkedHashMap的源码可以参考文章:HashMap源码 - 简书
接下来,我们查看entryRemoved方法和trimToSize方法:
protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
entryRemoved方法在LruCache中什么也没有处理,这个方法的作用就是每次我们从缓存中将最近最久未使用的移除缓存时调用的方法,我们可以利用此方法对移除缓存的数据做处理。其中evicted表示该key-value是否移除(true移除)
图2在图2的trimToSize方法中,我们可以看到size会和我们设置的maxSize进行比较,并不断移除LinkedHashMap中的最近最久未使用的(即头部节点),直到size<=maxSize,从而来保证缓存的大小不超过我们设置的缓存最大值。
图3在图3的get方法中,可以看到内部调用的是LinkedHashMap的get方法,在LinkedHashMap源码中可以看到每一次调用get方法获取到key对应的值,就会调整该Node的before和after,其实并没有改变该Node的实际存储位置,只不过改变了该Node获取的顺序。听起来有些绕口,需要你去看HashMap和LinkedHashMap的源码就会理解。简单说为了能够按照put数据的顺序取出数据,在LinkedHashMap中引入了头部节点和尾部节点,并在节点中多保存了它对应的前一个节点和后一个节点。在LinkedHashMap中调用get方法时便将该Node放到尾部节点,从而使得最近最久未使用的节点在头部节点。