Bitmap处理之创建可自动回收资源的ImageView

来源:互联网 发布:json返回html标签 编辑:程序博客网 时间:2024/06/06 11:57

转载地址:http://blog.csdn.net/android_learn/article/details/8837234#t5

[-]

  1. 创建可自动回收资源的BitmapDrawable
    1. 判断bitmap是否还存在并且可用
    2. 判断bitmap的状态
    3. 判断bitmap是否已经cache
    4. 判断bitmap是否已经显示
      1. 完整的代码
    5. 创建可自动回收资源的ImageView

1.创建可自动回收资源的BitmapDrawable

继承BitmapDrawable,设置标志位 mCacheRefCount cache计数,mDisplayRefCount 显示计数,mHasBeenDisplayed判断是否已经显示过了具体的code:

[java] view plaincopyprint?
  1. private int mCacheRefCount = 0;  //cache计数  
  2. private int mDisplayRefCount = 0//显示计数  
  3.   
  4. private boolean mHasBeenDisplayed;//是否已经显示过  

判断bitmap是否还存在并且可用

[java] view plaincopyprint?
  1. private synchronized boolean hasValidBitmap() {  
  2.     Bitmap bitmap = getBitmap();  
  3.     return bitmap != null && !bitmap.isRecycled();  
  4. }  

判断bitmap的状态

[java] view plaincopyprint?
  1. private synchronized void checkState() {  
  2.     // If the drawable cache and display ref counts = 0, and this drawable  
  3.     // has been displayed, then recycle  
  4.     if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed  
  5.             && hasValidBitmap()) {  
  6.   
  7.         getBitmap().recycle();  
  8.     }  
  9. }  

通过cache计数,显示计数,是否已经显示,以及bitmap是否还存在,如果四个条件都满足,就显式的回收bitmap资源


判断bitmap是否已经cache

[java] view plaincopyprint?
  1. public void setIsCached(boolean isCached) {  
  2.     synchronized (this) {  
  3.         if (isCached) {  
  4.             mCacheRefCount++;  
  5.         } else {  
  6.             mCacheRefCount--;  
  7.         }  
  8.     }  
  9.   
  10.     // Check to see if recycle() can be called  
  11.     checkState();  
  12. }  

调用的地方是,如果已经将某个bitmap加入了cache(memory cache,disk cache)setIsCached(true)这时cache计数就会增加1,如果某个bitmap从cache中删除,就setIsCached(false)这时cache计数就减去1,然后调用checkState()方法,来判断bitmap是否需要回收

判断bitmap是否已经显示


[java] view plaincopyprint?
  1. public void setIsDisplayed(boolean isDisplayed) {  
  2.     synchronized (this) {  
  3.         if (isDisplayed) {  
  4.             mDisplayRefCount++;  
  5.             mHasBeenDisplayed = true;  
  6.         } else {  
  7.             mDisplayRefCount--;  
  8.         }  
  9.     }  
  10.   
  11.     // Check to see if recycle() can be called  
  12.     checkState();  
  13. }  

完整的代码

[java] view plaincopyprint?
  1. public class RecyclingBitmapDrawable extends BitmapDrawable {  
  2.   
  3.     static final String LOG_TAG = "CountingBitmapDrawable";  
  4.   
  5.     private int mCacheRefCount = 0;  
  6.     private int mDisplayRefCount = 0;  
  7.   
  8.     private boolean mHasBeenDisplayed;  
  9.   
  10.     public RecyclingBitmapDrawable(Resources res, Bitmap bitmap) {  
  11.         super(res, bitmap);  
  12.     }  
  13.   
  14.     /** 
  15.      * Notify the drawable that the displayed state has changed. Internally a 
  16.      * count is kept so that the drawable knows when it is no longer being 
  17.      * displayed. 
  18.      * 
  19.      * @param isDisplayed - Whether the drawable is being displayed or not 
  20.      */  
  21.     public void setIsDisplayed(boolean isDisplayed) {  
  22.         synchronized (this) {  
  23.             if (isDisplayed) {  
  24.                 mDisplayRefCount++;  
  25.                 mHasBeenDisplayed = true;  
  26.             } else {  
  27.                 mDisplayRefCount--;  
  28.             }  
  29.         }  
  30.   
  31.         // Check to see if recycle() can be called  
  32.         checkState();  
  33.     }  
  34.   
  35.     /** 
  36.      * Notify the drawable that the cache state has changed. Internally a count 
  37.      * is kept so that the drawable knows when it is no longer being cached. 
  38.      * 
  39.      * @param isCached - Whether the drawable is being cached or not 
  40.      */  
  41.     public void setIsCached(boolean isCached) {  
  42.         synchronized (this) {  
  43.             if (isCached) {  
  44.                 mCacheRefCount++;  
  45.             } else {  
  46.                 mCacheRefCount--;  
  47.             }  
  48.         }  
  49.   
  50.         // Check to see if recycle() can be called  
  51.         checkState();  
  52.     }  
  53.   
  54.     private synchronized void checkState() {  
  55.         // If the drawable cache and display ref counts = 0, and this drawable  
  56.         // has been displayed, then recycle  
  57.         if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed  
  58.                 && hasValidBitmap()) {  
  59.             if (BuildConfig.DEBUG) {  
  60.                 Log.d(LOG_TAG, "No longer being used or cached so recycling. "  
  61.                         + toString());  
  62.             }  
  63.   
  64.             getBitmap().recycle();  
  65.         }  
  66.     }  
  67.   
  68.     private synchronized boolean hasValidBitmap() {  
  69.         Bitmap bitmap = getBitmap();  
  70.         return bitmap != null && !bitmap.isRecycled();  
  71.     }  
  72.   
  73. }  


2.创建可自动回收资源的ImageView

基于RecyclingBitmapDrawable来实现 RecyclingImageView

具体实现

重载Imageiew的setImageDrawable()方法

[java] view plaincopyprint?
  1. public void setImageDrawable(Drawable drawable) {  
  2.     // Keep hold of previous Drawable  
  3.     final Drawable previousDrawable = getDrawable();  
  4.   
  5.     // Call super to set new Drawable  
  6.     super.setImageDrawable(drawable);  
  7.   
  8.     // Notify new Drawable that it is being displayed  
  9.     notifyDrawable(drawable, true);  
  10.   
  11.     // Notify old Drawable so it is no longer being displayed  
  12.     notifyDrawable(previousDrawable, false);  
  13. }  
在设置时,显获得前一个drawable资源,然后发出通知,通知的是实现

[java] view plaincopyprint?
  1. private static void notifyDrawable(Drawable drawable, final boolean isDisplayed) {  
  2.     if (drawable instanceof RecyclingBitmapDrawable) {  
  3.         // The drawable is a CountingBitmapDrawable, so notify it  
  4.         ((RecyclingBitmapDrawable) drawable).setIsDisplayed(isDisplayed);  
  5.     } else if (drawable instanceof LayerDrawable) {  
  6.         // The drawable is a LayerDrawable, so recurse on each layer  
  7.         LayerDrawable layerDrawable = (LayerDrawable) drawable;  
  8.         for (int i = 0, z = layerDrawable.getNumberOfLayers(); i < z; i++) {  
  9.             notifyDrawable(layerDrawable.getDrawable(i), isDisplayed);  
  10.         }  
  11.     }  
  12. }  
主要是调用RecyclingBitmapDrawable的setIsDisplayed方法,在通过ImageView设置时,当前的Drawable的显示计数加1,而前一个Drawable资源的显示计数减1,然后检查状态,这样前一个Drawable资源就有可能被回收


http://developer.android.com/training/displaying-bitmaps/process-bitmap.html#concurrency
0 0