转载地址:http://blog.csdn.net/android_learn/article/details/8837234#t5
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);
- }
- 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);
- }
- }
- }