privateintmCacheRefCount=0;privateintmDisplayRefCount=0;...// Notify the drawable that the displayed state has changed.// Keep a count to determine when the drawable is no longer displayed.publicvoidsetIsDisplayed(booleanisDisplayed){synchronized(this){if(isDisplayed){mDisplayRefCount++;mHasBeenDisplayed=true;}else{mDisplayRefCount--;}}// Check to see if recycle() can be called.checkState();}// Notify the drawable that the cache state has changed.// Keep a count to determine when the drawable is no longer being cached.publicvoidsetIsCached(booleanisCached){synchronized(this){if(isCached){mCacheRefCount++;}else{mCacheRefCount--;}}// Check to see if recycle() can be called.checkState();}privatesynchronizedvoidcheckState(){// If the drawable cache and display ref counts = 0, and this drawable// has been displayed, then recycle.if(mCacheRefCount<=0&&mDisplayRefCount<=0&&mHasBeenDisplayed&&hasValidBitmap()){getBitmap().recycle();}}privatesynchronizedbooleanhasValidBitmap(){Bitmapbitmap=getBitmap();returnbitmap!=null&&!bitmap.isRecycled();}
HashSet<SoftReference<Bitmap>>mReusableBitmaps;privateLruCache<String,BitmapDrawable>mMemoryCache;// If you're running on Honeycomb or newer, create// a HashSet of references to reusable bitmaps.if(Utils.hasHoneycomb()){mReusableBitmaps=newHashSet<SoftReference<Bitmap>>();}mMemoryCache=newLruCache<String,BitmapDrawable>(mCacheParams.memCacheSize){// Notify the removed entry that is no longer being cached.@OverrideprotectedvoidentryRemoved(booleanevicted,Stringkey,BitmapDrawableoldValue,BitmapDrawablenewValue){if(RecyclingBitmapDrawable.class.isInstance(oldValue)){// The removed entry is a recycling drawable, so notify it// that it has been removed from the memory cache.((RecyclingBitmapDrawable)oldValue).setIsCached(false);}else{// The removed entry is a standard BitmapDrawable.if(Utils.hasHoneycomb()){// We're running on Honeycomb or later, so add the bitmap// to a SoftReference set for possible use with inBitmap later.mReusableBitmaps.add(newSoftReference<Bitmap>(oldValue.getBitmap()));}}}....}
Use an existing bitmap
在运行的程序中,decoder方法会去做检查看是否有可用的bitmap. 例如:
123456789101112131415
publicstaticBitmapdecodeSampledBitmapFromFile(Stringfilename,intreqWidth,intreqHeight,ImageCachecache){finalBitmapFactory.Optionsoptions=newBitmapFactory.Options();...BitmapFactory.decodeFile(filename,options);...// If we're running on Honeycomb or newer, try to use inBitmap.if(Utils.hasHoneycomb()){addInBitmapOptions(options,cache);}...returnBitmapFactory.decodeFile(filename,options);}
privatestaticvoidaddInBitmapOptions(BitmapFactory.Optionsoptions,ImageCachecache){// inBitmap only works with mutable bitmaps, so force the decoder to// return mutable bitmaps.options.inMutable=true;if(cache!=null){// Try to find a bitmap to use for inBitmap.BitmapinBitmap=cache.getBitmapFromReusableSet(options);if(inBitmap!=null){// If a suitable bitmap has been found, set it as the value of// inBitmap.options.inBitmap=inBitmap;}}}// This method iterates through the reusable bitmaps, looking for one // to use for inBitmap:protectedBitmapgetBitmapFromReusableSet(BitmapFactory.Optionsoptions){Bitmapbitmap=null;if(mReusableBitmaps!=null&&!mReusableBitmaps.isEmpty()){finalIterator<SoftReference<Bitmap>>iterator=mReusableBitmaps.iterator();Bitmapitem;while(iterator.hasNext()){item=iterator.next().get();if(null!=item&&item.isMutable()){// Check to see it the item can be used for inBitmap.if(canUseForInBitmap(item,options)){bitmap=item;// Remove from reusable set so it can't be used again.iterator.remove();break;}}else{// Remove from the set if the reference has been cleared.iterator.remove();}}}returnbitmap;}
最后,下面这个方法去判断候选bitmap是否满足inBitmap的大小条件:
123456789
privatestaticbooleancanUseForInBitmap(Bitmapcandidate,BitmapFactory.OptionstargetOptions){intwidth=targetOptions.outWidth/targetOptions.inSampleSize;intheight=targetOptions.outHeight/targetOptions.inSampleSize;// Returns true if "candidate" can be used for inBitmap re-use with// "targetOptions".returncandidate.getWidth()==width&&candidate.getHeight()==height;}