在Android 2.3.3,使用recycle()来释放Bitmap占用的内存,但是你必须要等到该Bitmap不再使用时,才可以使用recyle()来释放Bitma占用的内存,否则的话会引起错误。
我们经常会使用到同一张图片,而Bitmap的创建和销毁是比较占用内存的开销的,所以我们可以自定义一个可复用的BitmapDrawable来管理Bitmap,并且赋予它两个变量,一个的mDisplayRefCount,一个是mCacheRefCount,初始化为0。当以下两个条件都满足的时候,那么就可以回收该Bitmap所占用的内存。这两个条件是:
1、mDisplayRefCount和mCacheRefCount同时为0。
2、Bitmap不为null,而且还没有被回收。
以下代码

privateint mCacheRefCount =0; 

 privateint mDisplayRefCount =0; 

 ... 

 //通知该BitmapDrawable,显示状态已改变 

 publicvoid setIsDisplayed(boolean isDisplayed){ 

 synchronized(this){ 

 if(isDisplayed){ 

 mDisplayRefCount++; 

 mHasBeenDisplayed =true; 

 }else{ 

 mDisplayRefCount--; 

 } 

 } 

 //看看是否满足回收条件 

 checkState(); 

 } 


 //通知该BitmapDrawable,缓存状态已改变 

 publicvoid setIsCached(boolean isCached){ 

 synchronized(this){ 

 if(isCached){ 

 mCacheRefCount++; 

 }else{ 

 mCacheRefCount--; 

 } 

 } 

 //看看是否满足回收条件 

 checkState(); 

 } 


 privatesynchronizedvoid checkState(){ 

 if(mCacheRefCount <=0&& mDisplayRefCount <=0&& mHasBeenDisplayed 

 && hasValidBitmap()){ 

 getBitmap().recycle(); 

 } 

 } 


 privatesynchronizedboolean hasValidBitmap(){ 

 Bitmap bitmap = getBitmap(); 

 return bitmap !=null&&!bitmap.isRecycled(); 

 } 

 在Android3.0 之后,官方推荐使用BitmapFactory.Options.inBitmap这个字段来管理Bitmap的内存,该字段被使用后,那么Bitmap的解码方法将会使用Options来复用已经存在的Bitmap的内存空间,这将会提高App的性能。但是在使用inBitmap之前,我们要知道一些使用上的限制条件: 

 1、在Android4.4 (API 19)之前,使用的图片的宽高必须和被替换的Bitmap的宽高完全相同,而且使用的图片的Options.inSampleSize必须要为1。 

 2、在Android4.4 (API 19) 之后,使用的图片大小必须小于等于被替换的Bitmap的大小。 

 当一个应用运行在Android 3.0或者是更高的版本时,一张Bitmap的图片从LruCache中被移除的时候,那么该图片的软引用就会添加到一个HashSet中,以便该图片能够使用inBitmap进行复用。 

 我们看下面的代码(摘选自Android Developer) 

 Set<SoftReference<Bitmap>> mReusableBitmaps; 

 privateLruCache<String,BitmapDrawable> mMemoryCache; 


 //保证应用是运行在Android 3.0系统以上时,创建一个放置可复用Bitmap的同步HashSet 

 if(Utils.hasHoneycomb()){ 

 mReusableBitmaps = 

 Collections.synchronizedSet(newHashSet<SoftReference<Bitmap>>()); 

 } 


 mMemoryCache =newLruCache<String,BitmapDrawable>(mCacheParams.memCacheSize){ 

 //当Bitmap从LruCache中被移除时,该回调方法被调用 

 @Override 

 protectedvoid entryRemoved(boolean evicted,String key, 

 BitmapDrawable oldValue,BitmapDrawable newValue){ 

 if(RecyclingBitmapDrawable.class.isInstance(oldValue)){ 

 //如果被移除的实例属于RecylingBitmapDrawable这个类,那么通知它,它已经从LruCache被移出了 

 ((RecyclingBitmapDrawable) oldValue).setIsCached(false); 

 }else{ 

 //如果被移除的实例属于一个标准的BitmapDrawable,而且应用是运行在Android 3.0系统以上 

 //再次判断是否运行在Android 3.0系统以上是保证mResuableBitmaps不为空 

 if(Utils.hasHoneycomb()){ 

 //将该Bitmap的软引用添加到HashSet中,以便以后使用inBitmap可以复用内存空间 

 mReusableBitmaps.add 

 (newSoftReference<Bitmap>(oldValue.getBitmap())); 

 } 

 } 

 } 

 .... 

 } 

 当我们要从文件或者资源解码Bitmap的时候,我们可以使用下面的解码方法来查看是否存在可以复用的Bitmap内存。以下代码摘自Android Developer。 

 publicstaticBitmap decodeSampledBitmapFromFile(String filename, 

 int reqWidth,int reqHeight,ImageCache cache){ 


 finalBitmapFactory.Options options =newBitmapFactory.Options(); 

 ... 

 BitmapFactory.decodeFile(filename, options); 

 ... 

 //当运行在Android 3.0系统以上的时候,我们才可以使用inBitmap 

 if(Utils.hasHoneycomb()){ 

 addInBitmapOptions(options, cache); 

 } 

 ... 

 returnBitmapFactory.decodeFile(filename, options); 

 } 

 addInBitmapOptions方法将从HashSet中寻找是否存在可以复用的Bitmap。在使用该方法返回的是一个Bitmap,但是该Bitmap有可能为空,所以我们必须要判断一下返回的Bitmap是否为空,否则会出现空指针异常。 

 privatestaticvoid addInBitmapOptions(BitmapFactory.Options options, 

 ImageCache cache){ 

 //inBitmap仅仅作用于可重用的Bitmap,所以这里我们强制让解码器给我们返回一个可重用的Bitmap 

 options.inMutable =true; 


 if(cache !=null){ 

 //尝试从可复用的HashSet中寻找可复用的Bitmap内存 

 Bitmap inBitmap = cache.getBitmapFromReusableSet(options); 


 if(inBitmap !=null){ 

 // If a suitable bitmap has been found, set it as the value of 

 // inBitmap. 

 options.inBitmap = inBitmap; 

 } 

 } 

 } 

 //从可复用的Bitmaps中遍历,寻找是否存在有可以复用的inBitmap 

 protectedBitmap getBitmapFromReusableSet(BitmapFactory.Options options){ 

 Bitmap bitmap =null; 


 if(mReusableBitmaps !=null&&!mReusableBitmaps.isEmpty()){ 

 synchronized(mReusableBitmaps){ 

 finalIterator<SoftReference<Bitmap>> iterator 

 = mReusableBitmaps.iterator(); 

 Bitmap item; 


 while(iterator.hasNext()){ 

 item = iterator.next().get(); 


 if(null!= item && item.isMutable()){ 

 //查看该item是否可以作为inBitmap 

 if(canUseForInBitmap(item, options)){ 

 bitmap = item; 


 //从可复用的HashSet中删除item的软引用,让它不能再作为inBitmap 

 iterator.remove(); 

 break; 

 } 

 }else{ 

 //当该Item为空或者不是可变的时候,移除该item的软引用 

 iterator.remove(); 

 } 

 } 

 } 

 } 

 return bitmap; 

 } 

 最后地,该方法决定了candidate是否符合inBitmap的条件。 

 staticboolean canUseForInBitmap( 

 Bitmap candidate,BitmapFactory.Options targetOptions){ 


 if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.KITKAT){ 

 //从Android 4.4系统开始,新的Bitmap的大小可以小于等于可复用的Bitmap 

 int width = targetOptions.outWidth / targetOptions.inSampleSize; 

 int height = targetOptions.outHeight / targetOptions.inSampleSize; 

 int byteCount = width * height * getBytesPerPixel(candidate.getConfig()); 

 return byteCount <= candidate.getAllocationByteCount(); 

 } 

 //但是在Android 4.4系统以下,新的Bitmap的尺寸必须要刚好等于可复用的Bitmap,而且Options的inSamleSize的大小必须为1 

 return candidate.getWidth()== targetOptions.outWidth 

 && candidate.getHeight()== targetOptions.outHeight 

 && targetOptions.inSampleSize ==1; 

 } 


 /** 

 * 根据Bitmap的配置返回该Bitmap的每个像素占用多少个字节。 

 */ 

 staticint getBytesPerPixel(Config config){ 

 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; 

 }