1.创建可自动回收资源的BitmapDrawable
继承BitmapDrawable,设置标志位 mCacheRefCount cache计数,mDisplayRefCount 显示计数,mHasBeenDisplayed判断是否已经显示过了具体的code:
private int mCacheRefCount = 0; //cache计数 private int mDisplayRefCount = 0; //显示计数 private boolean mHasBeenDisplayed;//是否已经显示过
判断bitmap是否还存在并且可用
private synchronized boolean hasValidBitmap() { Bitmap bitmap = getBitmap(); return bitmap != null && !bitmap.isRecycled(); }
判断bitmap的状态
private synchronized void checkState() { // 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(); } }通过cache计数,显示计数,是否已经显示,以及bitmap是否还存在,如果四个条件都满足,就显式的回收bitmap资源
判断bitmap是否已经cache
public void setIsCached(boolean isCached) { synchronized (this) { if (isCached) { mCacheRefCount++; } else { mCacheRefCount--; } } // Check to see if recycle() can be called checkState(); }调用的地方是,如果已经将某个bitmap加入了cache(memory cache,disk cache)setIsCached(true)这时cache计数就会增加1,如果某个bitmap从cache中删除,就setIsCached(false)这时cache计数就减去1,然后调用checkState()方法,来判断bitmap是否需要回收
判断bitmap是否已经显示
public void setIsDisplayed(boolean isDisplayed) { synchronized (this) { if (isDisplayed) { mDisplayRefCount++; mHasBeenDisplayed = true; } else { mDisplayRefCount--; } } // Check to see if recycle() can be called checkState(); }
完整的代码
public class RecyclingBitmapDrawable extends BitmapDrawable { static final String LOG_TAG = "CountingBitmapDrawable"; private int mCacheRefCount = 0; private int mDisplayRefCount = 0; private boolean mHasBeenDisplayed; public RecyclingBitmapDrawable(Resources res, Bitmap bitmap) { super(res, bitmap); } /** * Notify the drawable that the displayed state has changed. Internally a * count is kept so that the drawable knows when it is no longer being * displayed. * * @param isDisplayed - Whether the drawable is being displayed or not */ public void setIsDisplayed(boolean isDisplayed) { 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. Internally a count * is kept so that the drawable knows when it is no longer being cached. * * @param isCached - Whether the drawable is being cached or not */ public void setIsCached(boolean isCached) { synchronized (this) { if (isCached) { mCacheRefCount++; } else { mCacheRefCount--; } } // Check to see if recycle() can be called checkState(); } private synchronized void checkState() { // If the drawable cache and display ref counts = 0, and this drawable // has been displayed, then recycle if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed && hasValidBitmap()) { if (BuildConfig.DEBUG) { Log.d(LOG_TAG, "No longer being used or cached so recycling. " + toString()); } getBitmap().recycle(); } } private synchronized boolean hasValidBitmap() { Bitmap bitmap = getBitmap(); return bitmap != null && !bitmap.isRecycled(); }}
2.创建可自动回收资源的ImageView
基于RecyclingBitmapDrawable来实现 RecyclingImageView
具体实现
重载Imageiew的setImageDrawable()方法
public void setImageDrawable(Drawable drawable) { // Keep hold of previous Drawable final Drawable previousDrawable = getDrawable(); // Call super to set new Drawable super.setImageDrawable(drawable); // Notify new Drawable that it is being displayed notifyDrawable(drawable, true); // Notify old Drawable so it is no longer being displayed notifyDrawable(previousDrawable, false); }在设置时,显获得前一个drawable资源,然后发出通知,通知的是实现
private static void notifyDrawable(Drawable drawable, final boolean isDisplayed) { if (drawable instanceof RecyclingBitmapDrawable) { // The drawable is a CountingBitmapDrawable, so notify it ((RecyclingBitmapDrawable) drawable).setIsDisplayed(isDisplayed); } else if (drawable instanceof LayerDrawable) { // The drawable is a LayerDrawable, so recurse on each layer LayerDrawable layerDrawable = (LayerDrawable) drawable; for (int i = 0, z = layerDrawable.getNumberOfLayers(); i < z; i++) { notifyDrawable(layerDrawable.getDrawable(i), isDisplayed); } } }主要是调用RecyclingBitmapDrawable的setIsDisplayed方法,在通过ImageView设置时,当前的Drawable的显示计数加1,而前一个Drawable资源的显示计数减1,然后检查状态,这样前一个Drawable资源就有可能被回收