Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.displayingbitmaps.util;
     18 
     19 import android.content.res.Resources;
     20 import android.graphics.Bitmap;
     21 import android.graphics.drawable.BitmapDrawable;
     22 
     23 import com.example.android.common.logger.Log;
     24 import com.example.android.displayingbitmaps.BuildConfig;
     25 
     26 /**
     27  * A BitmapDrawable that keeps track of whether it is being displayed or cached.
     28  * When the drawable is no longer being displayed or cached,
     29  * {@link android.graphics.Bitmap#recycle() recycle()} will be called on this drawable's bitmap.
     30  */
     31 public class RecyclingBitmapDrawable extends BitmapDrawable {
     32 
     33     static final String TAG = "CountingBitmapDrawable";
     34 
     35     private int mCacheRefCount = 0;
     36     private int mDisplayRefCount = 0;
     37 
     38     private boolean mHasBeenDisplayed;
     39 
     40     public RecyclingBitmapDrawable(Resources res, Bitmap bitmap) {
     41         super(res, bitmap);
     42     }
     43 
     44     /**
     45      * Notify the drawable that the displayed state has changed. Internally a
     46      * count is kept so that the drawable knows when it is no longer being
     47      * displayed.
     48      *
     49      * @param isDisplayed - Whether the drawable is being displayed or not
     50      */
     51     public void setIsDisplayed(boolean isDisplayed) {
     52         //BEGIN_INCLUDE(set_is_displayed)
     53         synchronized (this) {
     54             if (isDisplayed) {
     55                 mDisplayRefCount++;
     56                 mHasBeenDisplayed = true;
     57             } else {
     58                 mDisplayRefCount--;
     59             }
     60         }
     61 
     62         // Check to see if recycle() can be called
     63         checkState();
     64         //END_INCLUDE(set_is_displayed)
     65     }
     66 
     67     /**
     68      * Notify the drawable that the cache state has changed. Internally a count
     69      * is kept so that the drawable knows when it is no longer being cached.
     70      *
     71      * @param isCached - Whether the drawable is being cached or not
     72      */
     73     public void setIsCached(boolean isCached) {
     74         //BEGIN_INCLUDE(set_is_cached)
     75         synchronized (this) {
     76             if (isCached) {
     77                 mCacheRefCount++;
     78             } else {
     79                 mCacheRefCount--;
     80             }
     81         }
     82 
     83         // Check to see if recycle() can be called
     84         checkState();
     85         //END_INCLUDE(set_is_cached)
     86     }
     87 
     88     private synchronized void checkState() {
     89         //BEGIN_INCLUDE(check_state)
     90         // If the drawable cache and display ref counts = 0, and this drawable
     91         // has been displayed, then recycle
     92         if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed
     93                 && hasValidBitmap()) {
     94             if (BuildConfig.DEBUG) {
     95                 Log.d(TAG, "No longer being used or cached so recycling. "
     96                         + toString());
     97             }
     98 
     99             getBitmap().recycle();
    100         }
    101         //END_INCLUDE(check_state)
    102     }
    103 
    104     private synchronized boolean hasValidBitmap() {
    105         Bitmap bitmap = getBitmap();
    106         return bitmap != null && !bitmap.isRecycled();
    107     }
    108 
    109 }
    110