DisplayingBitmaps / src / com.example.android.displayingbitmaps / util /

RecyclingBitmapDrawable.java

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
}