• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.bitmapfun.util;
18 
19 import android.content.res.Resources;
20 import android.graphics.Bitmap;
21 import android.graphics.drawable.BitmapDrawable;
22 import android.util.Log;
23 
24 import com.example.android.bitmapfun.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 Bitmap#recycle() recycle()} will be called on this drawable's bitmap.
30  */
31 public class RecyclingBitmapDrawable extends BitmapDrawable {
32 
33     static final String LOG_TAG = "CountingBitmapDrawable";
34 
35     private int mCacheRefCount = 0;
36     private int mDisplayRefCount = 0;
37 
38     private boolean mHasBeenDisplayed;
39 
RecyclingBitmapDrawable(Resources res, Bitmap bitmap)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      */
setIsDisplayed(boolean isDisplayed)51     public void setIsDisplayed(boolean isDisplayed) {
52         synchronized (this) {
53             if (isDisplayed) {
54                 mDisplayRefCount++;
55                 mHasBeenDisplayed = true;
56             } else {
57                 mDisplayRefCount--;
58             }
59         }
60 
61         // Check to see if recycle() can be called
62         checkState();
63     }
64 
65     /**
66      * Notify the drawable that the cache state has changed. Internally a count
67      * is kept so that the drawable knows when it is no longer being cached.
68      *
69      * @param isCached - Whether the drawable is being cached or not
70      */
setIsCached(boolean isCached)71     public void setIsCached(boolean isCached) {
72         synchronized (this) {
73             if (isCached) {
74                 mCacheRefCount++;
75             } else {
76                 mCacheRefCount--;
77             }
78         }
79 
80         // Check to see if recycle() can be called
81         checkState();
82     }
83 
checkState()84     private synchronized void checkState() {
85         // If the drawable cache and display ref counts = 0, and this drawable
86         // has been displayed, then recycle
87         if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed
88                 && hasValidBitmap()) {
89             if (BuildConfig.DEBUG) {
90                 Log.d(LOG_TAG, "No longer being used or cached so recycling. "
91                         + toString());
92             }
93 
94             getBitmap().recycle();
95         }
96     }
97 
hasValidBitmap()98     private synchronized boolean hasValidBitmap() {
99         Bitmap bitmap = getBitmap();
100         return bitmap != null && !bitmap.isRecycled();
101     }
102 
103 }
104