Java资源缓存 之 LruCache
程序员文章站
2024-03-13 18:37:33
例如对 网络加载图片进行缓存 :
// 得到 应用程序 被分配的最大的内存
int maxmemory=(int) runtime.getrunti...
例如对 网络加载图片进行缓存 :
// 得到 应用程序 被分配的最大的内存 int maxmemory=(int) runtime.getruntime().maxmemory(); // 取处内存的 1/5 用来当 缓存 大小 int cachsize=maxmemory/5; // 实例化 lrucache lrucache=new lrucache<string, bitmap>(cachsize){ //内部方法sizeof设置每一张图片的缓存大小 protected int sizeof(string key, bitmap value) { //在每次存入缓存时调用,告诉系统这张缓存图片有多大 // 相当于 为每次 要缓存的 资源 分配 大小空间 return value.getbytecount(); } };
上面的 代码 一般 放在初始化的 方法 里面
其实 可以将 lurcache 类 理解 为 map 类 map 有 put和 get 方法
接下去就调用put 和 get 方法 进行需要缓存资源的存取
lurcache 的 add :
public void putbitmaptocache(string url,bitmap bitmap){ if (getbitmapfromcache(url)==null) {//判断当前缓存是否存在 lrucache.put(url, bitmap); } } lurcache 的 get: public bitmap getbitmapfromcache(string url){ return lrucache.get(url);//可将lrucache看成map }
调用上面的 add 和 get 方法 就可以对资源进行缓存的 ,还是挺简单的,
但要注意一点 lrucache lrucache=new lrucache<string, bitmap>(cachsize)
只能被new 一次 ,不然不同对象就不同的缓存了
附上android的lrucache类
package android.util; import java.util.linkedhashmap; import java.util.map; /** * a cache that holds strong references to a limited number of values. each time * a value is accessed, it is moved to the head of a queue. when a value is * added to a full cache, the value at the end of that queue is evicted and may * become eligible for garbage collection. * cache保存一个强引用来限制内容数量,每当item被访问的时候,此item就会移动到队列的头部。 * 当cache已满的时候加入新的item时,在队列尾部的item会被回收。 * <p>if your cached values hold resources that need to be explicitly released, * override {@link #entryremoved}. * 如果你cache的某个值需要明确释放,重写entryremoved() * <p>if a cache miss should be computed on demand for the corresponding keys, * override {@link #create}. this simplifies the calling code, allowing it to * assume a value will always be returned, even when there's a cache miss. * 如果key相对应的item丢掉啦,重写create().这简化了调用代码,即使丢失了也总会返回。 * <p>by default, the cache size is measured in the number of entries. override * {@link #sizeof} to size the cache in different units. for example, this cache * is limited to 4mib of bitmaps: 默认cache大小是测量的item的数量,重写sizeof计算不同item的 * 大小。 * <pre> {@code * int cachesize = 4 * 1024 * 1024; // 4mib * lrucache<string, bitmap> bitmapcache = new lrucache<string, bitmap>(cachesize) { * protected int sizeof(string key, bitmap value) { * return value.getbytecount(); * } * }}</pre> * * <p>this class is thread-safe. perform multiple cache operations atomically by * synchronizing on the cache: <pre> {@code * synchronized (cache) { * if (cache.get(key) == null) { * cache.put(key, value); * } * }}</pre> * * <p>this class does not allow null to be used as a key or value. a return * value of null from {@link #get}, {@link #put} or {@link #remove} is * unambiguous: the key was not in the cache. * 不允许key或者value为null * 当get(),put(),remove()返回值为null时,key相应的项不在cache中 */ public class lrucache<k, v> { private final linkedhashmap<k, v> map; /** size of this cache in units. not necessarily the number of elements. */ private int size; //已经存储的大小 private int maxsize; //规定的最大存储空间 private int putcount; //put的次数 private int createcount; //create的次数 private int evictioncount; //回收的次数 private int hitcount; //命中的次数 private int misscount; //丢失的次数 /** * @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<k, v>(0, 0.75f, true); } /** * returns the value for {@code key} if it exists in the cache or can be * created by {@code #create}. if a value was returned, it is moved to the * head of the queue. this returns null if a value is not cached and cannot * be created. 通过key返回相应的item,或者创建返回相应的item。相应的item会移动到队列的头部, * 如果item的value没有被cache或者不能被创建,则返回null。 */ 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. * 如果丢失了就试图创建一个item */ v createdvalue = create(key); if (createdvalue == null) { return null; } synchronized (this) { createcount++;//创建++ mapvalue = map.put(key, createdvalue); if (mapvalue != null) { // there was a conflict so undo that last put //如果前面存在oldvalue,那么撤销put() map.put(key, mapvalue); } else { size += safesizeof(key, createdvalue); } } if (mapvalue != null) { entryremoved(false, key, createdvalue, mapvalue); return mapvalue; } else { trimtosize(maxsize); return createdvalue; } } /** * 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) { throw new nullpointerexception("key == null || value == null"); } v previous; synchronized (this) { putcount++; size += safesizeof(key, value); previous = map.put(key, value); if (previous != null) { //返回的先前的value值 size -= safesizeof(key, previous); } } if (previous != null) { entryremoved(false, key, previous, value); } trimtosize(maxsize); return previous; } /** * @param maxsize the maximum size of the cache before returning. may be -1 * to evict even 0-sized elements. * 清空cache空间 */ private void trimtosize(int maxsize) { while (true) { k key; v value; synchronized (this) { if (size < 0 || (map.isempty() && size != 0)) { throw new illegalstateexception(getclass().getname() + ".sizeof() is reporting inconsistent results!"); } if (size <= maxsize) { break; } map.entry<k, v> toevict = map.eldest(); if (toevict == null) { break; } key = toevict.getkey(); value = toevict.getvalue(); map.remove(key); size -= safesizeof(key, value); evictioncount++; } entryremoved(true, key, value, null); } } /** * removes the entry for {@code key} if it exists. * 删除key相应的cache项,返回相应的value * @return the previous value mapped by {@code key}. */ public final v remove(k key) { if (key == null) { throw new nullpointerexception("key == null"); } v previous; synchronized (this) { previous = map.remove(key); if (previous != null) { size -= safesizeof(key, previous); } } if (previous != null) { entryremoved(false, key, previous, null); } return previous; } /** * called for entries that have been evicted or removed. this method is * invoked when a value is evicted to make space, removed by a call to * {@link #remove}, or replaced by a call to {@link #put}. the default * implementation does nothing. * 当item被回收或者删掉时调用。改方法当value被回收释放存储空间时被remove调用, * 或者替换item值时put调用,默认实现什么都没做。 * <p>the method is called without synchronization: other threads may * access the cache while this method is executing. * * @param evicted true if the entry is being removed to make space, false * if the removal was caused by a {@link #put} or {@link #remove}. * true---为释放空间被删除;false---put或remove导致 * @param newvalue the new value for {@code key}, if it exists. if non-null, * this removal was caused by a {@link #put}. otherwise it was caused by * an eviction or a {@link #remove}. */ protected void entryremoved(boolean evicted, k key, v oldvalue, v newvalue) {} /** * called after a cache miss to compute a value for the corresponding key. * returns the computed value or null if no value can be computed. the * default implementation returns null. * 当某item丢失时会调用到,返回计算的相应的value或者null * <p>the method is called without synchronization: other threads may * access the cache while this method is executing. * * <p>if a value for {@code key} exists in the cache when this method * returns, the created value will be released with {@link #entryremoved} * and discarded. this can occur when multiple threads request the same key * at the same time (causing multiple values to be created), or when one * thread calls {@link #put} while another is creating a value for the same * key. */ protected v create(k key) { return null; } private int safesizeof(k key, v value) { int result = sizeof(key, value); if (result < 0) { throw new illegalstateexception("negative size: " + key + "=" + value); } return result; } /** * returns the size of the entry for {@code key} and {@code value} in * user-defined units. the default implementation returns 1 so that size * is the number of entries and max size is the maximum number of entries. * 返回用户定义的item的大小,默认返回1代表item的数量,最大size就是最大item值 * <p>an entry's size must not change while it is in the cache. */ protected int sizeof(k key, v value) { return 1; } /** * clear the cache, calling {@link #entryremoved} on each removed entry. * 清空cacke */ public final void evictall() { trimtosize(-1); // -1 will evict 0-sized elements } /** * for caches that do not override {@link #sizeof}, this returns the number * of entries in the cache. for all other caches, this returns the sum of * the sizes of the entries in this cache. */ public synchronized final int size() { return size; } /** * for caches that do not override {@link #sizeof}, this returns the maximum * number of entries in the cache. for all other caches, this returns the * maximum sum of the sizes of the entries in this cache. */ public synchronized final int maxsize() { return maxsize; } /** * returns the number of times {@link #get} returned a value that was * already present in the cache. */ public synchronized final int hitcount() { return hitcount; } /** * returns the number of times {@link #get} returned null or required a new * value to be created. */ public synchronized final int misscount() { return misscount; } /** * returns the number of times {@link #create(object)} returned a value. */ public synchronized final int createcount() { return createcount; } /** * returns the number of times {@link #put} was called. */ public synchronized final int putcount() { return putcount; } /** * returns the number of values that have been evicted. * 返回被回收的数量 */ public synchronized final int evictioncount() { return evictioncount; } /** * returns a copy of the current contents of the cache, ordered from least * recently accessed to most recently accessed. 返回当前cache的副本,从最近最少访问到最多访问 */ public synchronized final map<k, v> snapshot() { return new linkedhashmap<k, v>(map); } @override public synchronized final string tostring() { int accesses = hitcount + misscount; int hitpercent = accesses != 0 ? (100 * hitcount / accesses) : 0; return string.format("lrucache[maxsize=%d,hits=%d,misses=%d,hitrate=%d%%]", maxsize, hitcount, misscount, hitpercent); } }