blob: 5534a6aeabc408f6fdbec3692f235ff7962a7ff7 [file] [log] [blame]
Alexander Lucas97842ff2014-03-07 14:56:55 -08001/*
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
17package com.example.android.displayingbitmaps.util;
18
19import android.content.res.Resources;
20import android.graphics.Bitmap;
21import android.graphics.drawable.BitmapDrawable;
22
23import com.example.android.common.logger.Log;
24import 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 */
31public 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}