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
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資源就有可能被回收