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) {
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();
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) {
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();
86
}
87
88
private synchronized void checkState() {
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
}
102
}
103
104
private synchronized boolean hasValidBitmap() {
105
Bitmap bitmap = getBitmap();
106
return bitmap != null && !bitmap.isRecycled();
107
}
108
109
}