1package com.bumptech.glide.load.engine.bitmap_recycle;
2
3import android.graphics.Bitmap;
4import android.os.Build;
5import android.util.Log;
6
7import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
8import static android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE;
9
10public class LruBitmapPool implements BitmapPool {
11    private static final String TAG = "LruBitmapPool";
12    private final LruPoolStrategy strategy;
13
14    private final int initialMaxSize;
15    private int maxSize;
16    private int currentSize = 0;
17    private int hits;
18    private int misses;
19    private int puts;
20    private int evictions;
21
22    // Exposed for testing only.
23    LruBitmapPool(int maxSize, LruPoolStrategy strategy) {
24        this.initialMaxSize = maxSize;
25        this.maxSize = maxSize;
26        this.strategy = strategy;
27    }
28
29    public LruBitmapPool(int maxSize) {
30        initialMaxSize = maxSize;
31        this.maxSize = maxSize;
32        if (Build.VERSION.SDK_INT >= 19) {
33            strategy = new SizeStrategy();
34        } else {
35            strategy = new AttributeStrategy();
36        }
37    }
38
39    @Override
40    public void setSizeMultiplier(float sizeMultiplier) {
41        maxSize = Math.round(initialMaxSize * sizeMultiplier);
42        evict();
43    }
44
45    @Override
46    public synchronized boolean put(Bitmap bitmap) {
47        if (!bitmap.isMutable() || strategy.getSize(bitmap) > maxSize) {
48            return false;
49        }
50
51        final int size = strategy.getSize(bitmap);
52        strategy.put(bitmap);
53
54        puts++;
55        currentSize += size;
56
57        if (Log.isLoggable(TAG, Log.DEBUG)) {
58            Log.d(TAG, "Put bitmap in pool=" + strategy.logBitmap(bitmap));
59        }
60        dump();
61
62        evict();
63        return true;
64    }
65
66    private void evict() {
67        trimToSize(maxSize);
68    }
69
70    @Override
71    public synchronized Bitmap get(int width, int height, Bitmap.Config config) {
72        final Bitmap result = strategy.get(width, height, config);
73        if (result == null) {
74            if (Log.isLoggable(TAG, Log.DEBUG)) {
75                Log.d(TAG, "Missing bitmap=" + strategy.logBitmap(width, height, config));
76            }
77            misses++;
78        } else {
79            hits++;
80            currentSize -= strategy.getSize(result);
81        }
82        if (Log.isLoggable(TAG, Log.DEBUG)) {
83            Log.d(TAG, "Get bitmap=" + strategy.logBitmap(width, height, config));
84        }
85        dump();
86
87        return result;
88    }
89
90    @Override
91    public void clearMemory() {
92        trimToSize(0);
93    }
94
95    @Override
96    public void trimMemory(int level) {
97        if (level >= TRIM_MEMORY_MODERATE) {
98            clearMemory();
99        } else if (level >= TRIM_MEMORY_BACKGROUND) {
100            trimToSize(maxSize / 2);
101        }
102    }
103
104    private void trimToSize(int size) {
105        while (currentSize > size) {
106            final Bitmap removed = strategy.removeLast();
107            currentSize -= strategy.getSize(removed);
108            removed.recycle();
109            evictions++;
110            if (Log.isLoggable(TAG, Log.DEBUG)) {
111                Log.d(TAG, "Evicting bitmap=" + strategy.logBitmap(removed));
112            }
113            dump();
114        }
115    }
116
117    private void dump() {
118        if (Log.isLoggable(TAG, Log.VERBOSE)) {
119            Log.v(TAG, "Hits=" + hits + " misses=" + misses + " puts=" + puts + " evictions=" + evictions + " currentSize="
120                    + currentSize + " maxSize=" + maxSize + "\nStrategy=" + strategy);
121        }
122    }
123}
124