Java资源缓存 之 LruCache
例如对网络加载图片进行缓存:
//得到应用程序被分配的最大的内存
intmaxMemory=(int)Runtime.getRuntime().maxMemory();
//取处内存的1/5用来当缓存大小
intcachSize=maxMemory/5;
//实例化LruCache
lruCache=newlruCache<String,Bitmap>(cachSize){
//内部方法sizeOf设置每一张图片的缓存大小
protectedintsizeOf(Stringkey,Bitmapvalue){
//在每次存入缓存时调用,告诉系统这张缓存图片有多大
//相当于为每次要缓存的资源分配大小空间
returnvalue.getByteCount();
}
};
上面的代码一般放在初始化的方法里面
其实可以将LurCache类理解为Map类map有put和get方法
接下去就调用put和get方法进行需要缓存资源的存取
LurCache的add:
publicvoidputBitmapToCache(Stringurl,Bitmapbitmap){
if(getBitmapfromCache(url)==null){//判断当前缓存是否存在
lruCache.put(url,bitmap);
}
}
LurCache的get:
publicBitmapgetBitmapfromCache(Stringurl){
returnlruCache.get(url);//可将lruCache看成map
}
调用上面的add和get方法就可以对资源进行缓存的,还是挺简单的,
但要注意一点LruCachelruCache=newLruCache<String,Bitmap>(cachSize)只能被new一次,不然不同对象就不同的缓存了
附上Android的Lrucache类
packageandroid.util;
importjava.util.LinkedHashMap;
importjava.util.Map;
/**
*Acachethatholdsstrongreferencestoalimitednumberofvalues.Eachtime
*avalueisaccessed,itismovedtotheheadofaqueue.Whenavalueis
*addedtoafullcache,thevalueattheendofthatqueueisevictedandmay
*becomeeligibleforgarbagecollection.
*Cache保存一个强引用来限制内容数量,每当Item被访问的时候,此Item就会移动到队列的头部。
*当cache已满的时候加入新的item时,在队列尾部的item会被回收。
*<p>Ifyourcachedvaluesholdresourcesthatneedtobeexplicitlyreleased,
*override{@link#entryRemoved}.
*如果你cache的某个值需要明确释放,重写entryRemoved()
*<p>Ifacachemissshouldbecomputedondemandforthecorrespondingkeys,
*override{@link#create}.Thissimplifiesthecallingcode,allowingitto
*assumeavaluewillalwaysbereturned,evenwhenthere'sacachemiss.
*如果key相对应的item丢掉啦,重写create().这简化了调用代码,即使丢失了也总会返回。
*<p>Bydefault,thecachesizeismeasuredinthenumberofentries.Override
*{@link#sizeOf}tosizethecacheindifferentunits.Forexample,thiscache
*islimitedto4MiBofbitmaps:默认cache大小是测量的item的数量,重写sizeof计算不同item的
*大小。
*<pre>{@code
*intcacheSize=4*1024*1024;//4MiB
*LruCache<String,Bitmap>bitmapCache=newLruCache<String,Bitmap>(cacheSize){
*protectedintsizeOf(Stringkey,Bitmapvalue){
*returnvalue.getByteCount();
*}
*}}</pre>
*
*<p>Thisclassisthread-safe.Performmultiplecacheoperationsatomicallyby
*synchronizingonthecache:<pre>{@code
*synchronized(cache){
*if(cache.get(key)==null){
*cache.put(key,value);
*}
*}}</pre>
*
*<p>Thisclassdoesnotallownulltobeusedasakeyorvalue.Areturn
*valueofnullfrom{@link#get},{@link#put}or{@link#remove}is
*unambiguous:thekeywasnotinthecache.
*不允许key或者value为null
*当get(),put(),remove()返回值为null时,key相应的项不在cache中
*/
publicclassLruCache<K,V>{
privatefinalLinkedHashMap<K,V>map;
/**Sizeofthiscacheinunits.Notnecessarilythenumberofelements.*/
privateintsize;//已经存储的大小
privateintmaxSize;//规定的最大存储空间
privateintputCount;//put的次数
privateintcreateCount;//create的次数
privateintevictionCount;//回收的次数
privateinthitCount;//命中的次数
privateintmissCount;//丢失的次数
/**
*@parammaxSizeforcachesthatdonotoverride{@link#sizeOf},thisis
*themaximumnumberofentriesinthecache.Forallothercaches,
*thisisthemaximumsumofthesizesoftheentriesinthiscache.
*/
publicLruCache(intmaxSize){
if(maxSize<=0){
thrownewIllegalArgumentException("maxSize<=0");
}
this.maxSize=maxSize;
this.map=newLinkedHashMap<K,V>(0,0.75f,true);
}
/**
*Returnsthevaluefor{@codekey}ifitexistsinthecacheorcanbe
*createdby{@code#create}.Ifavaluewasreturned,itismovedtothe
*headofthequeue.Thisreturnsnullifavalueisnotcachedandcannot
*becreated.通过key返回相应的item,或者创建返回相应的item。相应的item会移动到队列的头部,
*如果item的value没有被cache或者不能被创建,则返回null。
*/
publicfinalVget(Kkey){
if(key==null){
thrownewNullPointerException("key==null");
}
VmapValue;
synchronized(this){
mapValue=map.get(key);
if(mapValue!=null){
hitCount++;//命中
returnmapValue;
}
missCount++;//丢失
}
/*
*Attempttocreateavalue.Thismaytakealongtime,andthemap
*maybedifferentwhencreate()returns.Ifaconflictingvaluewas
*addedtothemapwhilecreate()wasworking,weleavethatvaluein
*themapandreleasethecreatedvalue.
*如果丢失了就试图创建一个item
*/
VcreatedValue=create(key);
if(createdValue==null){
returnnull;
}
synchronized(this){
createCount++;//创建++
mapValue=map.put(key,createdValue);
if(mapValue!=null){
//Therewasaconflictsoundothatlastput
//如果前面存在oldValue,那么撤销put()
map.put(key,mapValue);
}else{
size+=safeSizeOf(key,createdValue);
}
}
if(mapValue!=null){
entryRemoved(false,key,createdValue,mapValue);
returnmapValue;
}else{
trimToSize(maxSize);
returncreatedValue;
}
}
/**
*Caches{@codevalue}for{@codekey}.Thevalueismovedtotheheadof
*thequeue.
*
*@returnthepreviousvaluemappedby{@codekey}.
*/
publicfinalVput(Kkey,Vvalue){
if(key==null||value==null){
thrownewNullPointerException("key==null||value==null");
}
Vprevious;
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);
returnprevious;
}
/**
*@parammaxSizethemaximumsizeofthecachebeforereturning.Maybe-1
*toevicteven0-sizedelements.
*清空cache空间
*/
privatevoidtrimToSize(intmaxSize){
while(true){
Kkey;
Vvalue;
synchronized(this){
if(size<0||(map.isEmpty()&&size!=0)){
thrownewIllegalStateException(getClass().getName()
+".sizeOf()isreportinginconsistentresults!");
}
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);
}
}
/**
*Removestheentryfor{@codekey}ifitexists.
*删除key相应的cache项,返回相应的value
*@returnthepreviousvaluemappedby{@codekey}.
*/
publicfinalVremove(Kkey){
if(key==null){
thrownewNullPointerException("key==null");
}
Vprevious;
synchronized(this){
previous=map.remove(key);
if(previous!=null){
size-=safeSizeOf(key,previous);
}
}
if(previous!=null){
entryRemoved(false,key,previous,null);
}
returnprevious;
}
/**
*Calledforentriesthathavebeenevictedorremoved.Thismethodis
*invokedwhenavalueisevictedtomakespace,removedbyacallto
*{@link#remove},orreplacedbyacallto{@link#put}.Thedefault
*implementationdoesnothing.
*当item被回收或者删掉时调用。改方法当value被回收释放存储空间时被remove调用,
*或者替换item值时put调用,默认实现什么都没做。
*<p>Themethodiscalledwithoutsynchronization:otherthreadsmay
*accessthecachewhilethismethodisexecuting.
*
*@paramevictedtrueiftheentryisbeingremovedtomakespace,false
*iftheremovalwascausedbya{@link#put}or{@link#remove}.
*true---为释放空间被删除;false---put或remove导致
*@paramnewValuethenewvaluefor{@codekey},ifitexists.Ifnon-null,
*thisremovalwascausedbya{@link#put}.Otherwiseitwascausedby
*anevictionora{@link#remove}.
*/
protectedvoidentryRemoved(booleanevicted,Kkey,VoldValue,VnewValue){}
/**
*Calledafteracachemisstocomputeavalueforthecorrespondingkey.
*Returnsthecomputedvalueornullifnovaluecanbecomputed.The
*defaultimplementationreturnsnull.
*当某Item丢失时会调用到,返回计算的相应的value或者null
*<p>Themethodiscalledwithoutsynchronization:otherthreadsmay
*accessthecachewhilethismethodisexecuting.
*
*<p>Ifavaluefor{@codekey}existsinthecachewhenthismethod
*returns,thecreatedvaluewillbereleasedwith{@link#entryRemoved}
*anddiscarded.Thiscanoccurwhenmultiplethreadsrequestthesamekey
*atthesametime(causingmultiplevaluestobecreated),orwhenone
*threadcalls{@link#put}whileanotheriscreatingavalueforthesame
*key.
*/
protectedVcreate(Kkey){
returnnull;
}
privateintsafeSizeOf(Kkey,Vvalue){
intresult=sizeOf(key,value);
if(result<0){
thrownewIllegalStateException("Negativesize:"+key+"="+value);
}
returnresult;
}
/**
*Returnsthesizeoftheentryfor{@codekey}and{@codevalue}in
*user-definedunits.Thedefaultimplementationreturns1sothatsize
*isthenumberofentriesandmaxsizeisthemaximumnumberofentries.
*返回用户定义的item的大小,默认返回1代表item的数量,最大size就是最大item值
*<p>Anentry'ssizemustnotchangewhileitisinthecache.
*/
protectedintsizeOf(Kkey,Vvalue){
return1;
}
/**
*Clearthecache,calling{@link#entryRemoved}oneachremovedentry.
*清空cacke
*/
publicfinalvoidevictAll(){
trimToSize(-1);//-1willevict0-sizedelements
}
/**
*Forcachesthatdonotoverride{@link#sizeOf},thisreturnsthenumber
*ofentriesinthecache.Forallothercaches,thisreturnsthesumof
*thesizesoftheentriesinthiscache.
*/
publicsynchronizedfinalintsize(){
returnsize;
}
/**
*Forcachesthatdonotoverride{@link#sizeOf},thisreturnsthemaximum
*numberofentriesinthecache.Forallothercaches,thisreturnsthe
*maximumsumofthesizesoftheentriesinthiscache.
*/
publicsynchronizedfinalintmaxSize(){
returnmaxSize;
}
/**
*Returnsthenumberoftimes{@link#get}returnedavaluethatwas
*alreadypresentinthecache.
*/
publicsynchronizedfinalinthitCount(){
returnhitCount;
}
/**
*Returnsthenumberoftimes{@link#get}returnednullorrequiredanew
*valuetobecreated.
*/
publicsynchronizedfinalintmissCount(){
returnmissCount;
}
/**
*Returnsthenumberoftimes{@link#create(Object)}returnedavalue.
*/
publicsynchronizedfinalintcreateCount(){
returncreateCount;
}
/**
*Returnsthenumberoftimes{@link#put}wascalled.
*/
publicsynchronizedfinalintputCount(){
returnputCount;
}
/**
*Returnsthenumberofvaluesthathavebeenevicted.
*返回被回收的数量
*/
publicsynchronizedfinalintevictionCount(){
returnevictionCount;
}
/**
*Returnsacopyofthecurrentcontentsofthecache,orderedfromleast
*recentlyaccessedtomostrecentlyaccessed.返回当前cache的副本,从最近最少访问到最多访问
*/
publicsynchronizedfinalMap<K,V>snapshot(){
returnnewLinkedHashMap<K,V>(map);
}
@OverridepublicsynchronizedfinalStringtoString(){
intaccesses=hitCount+missCount;
inthitPercent=accesses!=0?(100*hitCount/accesses):0;
returnString.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
maxSize,hitCount,missCount,hitPercent);
}
}热门推荐
7 简短的二胎祝福语
10 简短霸气女儿生日 祝福语
11 祝福语高考小众诗句简短
12 元旦祝福语20秒简短
13 老师过年祝福语大全 简短
14 一生祝福语简短
15 产检祝福语简短霸气
16 朋友店开张祝福语简短
17 生日爱情祝福语大全简短
18 朋友女儿生日祝福语 简短