原文地址:http://developer.android.com/training/displaying-bitmaps/manage-memory.html

在图片缓存那节,已经介绍了关于垃圾回收和图片重用的一些问题,被推荐的策略是依赖于android的版本的BitmapFun例子就包行了如何有效的在不同android版本中展示图片。

先奠定本节课的基础,说明下如何在android中管理图片缓存:

1、在android2.2及之前的版本中,垃圾回收器要收集时,应用线程会被停止,这会导致延迟和性能降低。android2.3引入的并发式垃圾收集器,意味着如果图片不被引用将被立即回收。

2、在android2.3.3和之前的版本,返回的像素数据是存储在一个本地内存中。他是独立于位图本身的(位图本身是存储在虚拟机的堆栈中)。存储在本地内存中的像素数据不会有规律的被释放。这回导致应用可能超出他的内存限制并奔溃。从android3.0开始,像素数据存储在虚拟机的堆栈中与位图相关联。

下面将介绍如何在不同的android版本中操作图片缓存的管理。

在android2.3.3及之前管理图片缓存

在android2.3.3及之前的版本,使用recycle()是被推荐的,如果你的应用展示大量的图片,你可能会遇到内存溢出的问题。使用recycle()会使应用快速回收缓存。

使用recycle()时要确保图片对象不再被使用,他使用mDisplayRefCount和mCacheRefCount两个参数来判断图片是否在展示或是在缓存中。只有在以下条件满足时图片才会回收:

1、引用数mDisplayRefCount和mCacheRefcount为0

2、图片对象为null,还没被回收

privateintmCacheRefCount=0;privateintmDisplayRefCount=0;...//Notifythedrawablethatthedisplayedstatehaschanged.//Keepacounttodeterminewhenthedrawableisnolongerdisplayed.publicvoidsetIsDisplayed(booleanisDisplayed){synchronized(this){if(isDisplayed){mDisplayRefCount++;mHasBeenDisplayed=true;}else{mDisplayRefCount--;}}//Checktoseeifrecycle()canbecalled.checkState();}//Notifythedrawablethatthecachestatehaschanged.//Keepacounttodeterminewhenthedrawableisnolongerbeingcached.publicvoidsetIsCached(booleanisCached){synchronized(this){if(isCached){mCacheRefCount++;}else{mCacheRefCount--;}}//Checktoseeifrecycle()canbecalled.checkState();}privatesynchronizedvoidcheckState(){//Ifthedrawablecacheanddisplayrefcounts=0,andthisdrawable//hasbeendisplayed,thenrecycle.if(mCacheRefCount<=0&&mDisplayRefCount<=0&&mHasBeenDisplayed&&hasValidBitmap()){getBitmap().recycle();}}privatesynchronizedbooleanhasValidBitmap(){Bitmapbitmap=getBitmap();returnbitmap!=null&&!bitmap.isRecycled();}

在Android3.0及之后管理缓存

在android3.0包含了BitmapFactory.Options.InBitmap属性。如果设置了这个参数,解析时会试图重用以存在的缓存,这样图片缓存会被重复利用。然而使用inBitmap是有限制的。在Android4.4之前,只支持比较图片的大小。

保存一个图片为之后使用

接下来的例子将会介绍如何存储一个图片为之后使用。当应用是运行在Android3.0及之后的版本,并且图片是存储在LruCache中,那个一个软引用在HashSet的图片就有可能在之后被重用通过inBitmap参数。

Set<SoftReference<Bitmap>>mReusableBitmaps;privateLruCache<String,BitmapDrawable>mMemoryCache;//Ifyou'rerunningonHoneycombornewer,createa//synchronizedHashSetofreferencestoreusablebitmaps.if(Utils.hasHoneycomb()){mReusableBitmaps=Collections.synchronizedSet(newHashSet<SoftReference<Bitmap>>());}mMemoryCache=newLruCache<String,BitmapDrawable>(mCacheParams.memCacheSize){//Notifytheremovedentrythatisnolongerbeingcached.@OverrideprotectedvoidentryRemoved(booleanevicted,Stringkey,BitmapDrawableoldValue,BitmapDrawablenewValue){if(RecyclingBitmapDrawable.class.isInstance(oldValue)){//Theremovedentryisarecyclingdrawable,sonotifyit//thatithasbeenremovedfromthememorycache.((RecyclingBitmapDrawable)oldValue).setIsCached(false);}else{//TheremovedentryisastandardBitmapDrawable.if(Utils.hasHoneycomb()){//We'rerunningonHoneycomborlater,soaddthebitmap//toaSoftReferencesetforpossibleusewithinBitmaplater.mReusableBitmaps.add(newSoftReference<Bitmap>(oldValue.getBitmap()));}}}....}

使用一个已经存在的图片

publicstaticBitmapdecodeSampledBitmapFromFile(Stringfilename,intreqWidth,intreqHeight,ImageCachecache){finalBitmapFactory.Optionsoptions=newBitmapFactory.Options();...BitmapFactory.decodeFile(filename,options);...//Ifwe'rerunningonHoneycombornewer,trytouseinBitmap.if(Utils.hasHoneycomb()){addInBitmapOptions(options,cache);}...returnBitmapFactory.decodeFile(filename,options);}
privatestaticvoidaddInBitmapOptions(BitmapFactory.Optionsoptions,ImageCachecache){//inBitmaponlyworkswithmutablebitmaps,soforcethedecoderto//returnmutablebitmaps.options.inMutable=true;if(cache!=null){//TrytofindabitmaptouseforinBitmap.BitmapinBitmap=cache.getBitmapFromReusableSet(options);if(inBitmap!=null){//Ifasuitablebitmaphasbeenfound,setitasthevalueof//inBitmap.options.inBitmap=inBitmap;}}}//Thismethoditeratesthroughthereusablebitmaps,lookingforone//touseforinBitmap:protectedBitmapgetBitmapFromReusableSet(BitmapFactory.Optionsoptions){Bitmapbitmap=null;if(mReusableBitmaps!=null&&!mReusableBitmaps.isEmpty()){synchronized(mReusableBitmaps){finalIterator<SoftReference<Bitmap>>iterator=mReusableBitmaps.iterator();Bitmapitem;while(iterator.hasNext()){item=iterator.next().get();if(null!=item&&item.isMutable()){//ChecktoseeittheitemcanbeusedforinBitmap.if(canUseForInBitmap(item,options)){bitmap=item;//Removefromreusablesetsoitcan'tbeusedagain.iterator.remove();break;}}else{//Removefromthesetifthereferencehasbeencleared.iterator.remove();}}}}returnbitmap;}
staticbooleancanUseForInBitmap(Bitmapcandidate,BitmapFactory.OptionstargetOptions){if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT){//FromAndroid4.4(KitKat)onwardwecanre-useifthebytesizeof//thenewbitmapissmallerthanthereusablebitmapcandidate//allocationbytecount.intwidth=targetOptions.outWidth/targetOptions.inSampleSize;intheight=targetOptions.outHeight/targetOptions.inSampleSize;intbyteCount=width*height*getBytesPerPixel(candidate.getConfig());returnbyteCount<=candidate.getAllocationByteCount();}//Onearlierversions,thedimensionsmustmatchexactlyandtheinSampleSizemustbe1returncandidate.getWidth()==targetOptions.outWidth&&candidate.getHeight()==targetOptions.outHeight&&targetOptions.inSampleSize==1;}/***Ahelperfunctiontoreturnthebyteusageperpixelofabitmapbasedonitsconfiguration.*/staticintgetBytesPerPixel(Configconfig){if(config==Config.ARGB_8888){return4;}elseif(config==Config.RGB_565){return2;}elseif(config==Config.ARGB_4444){return2;}elseif(config==Config.ALPHA_8){return1;}return1;}


更多相关文章

  1. android 手势屏幕平移图片转换效果(也可以平移文本)
  2. android 图片透明
  3. Android实现图片轮播
  4. Android图片左右切换和拖动大小
  5. Android studio新版本 4.0安装和使用
  6. Android支持的图片格式
  7. Android——插入图片【ImageView】属性详解
  8. android图片透明度跟缩放大小动画事件

随机推荐

  1. 为可执行文件夹提供自定义图像
  2. java解析xml问题:如何获得一级标签下全部
  3. spring框架中一个跟String的trim方法一样
  4. java中的Unicode到String但很棘手
  5. hbase中出现的java.net.BindException-Pr
  6. 处理“您确定您想要离开这个页面”Msg在S
  7. javascript 操作流——回调的回调
  8. Java中字符流和字节流到底有什么区别!!!
  9. 5个java面试题。。。请高手给个答案。。
  10. java中匹配字符串中的中文字符(含中文标