-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathBitmapDiskCache.java
181 lines (148 loc) · 5.71 KB
/
BitmapDiskCache.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package com.github.gabrielbb;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Environment;
import com.jakewharton.disklrucache.DiskLruCache;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import static android.os.Environment.isExternalStorageRemovable;
public class BitmapDiskCache {
private DiskLruCache mDiskLruCache;
private final Object mDiskCacheLock = new Object();
private boolean mDiskCacheStarting = true;
private static final long DISK_CACHE_SIZE = 1024 * 1024 * 20; // 20MB
private static final String DISK_CACHE_SUBDIR = "BITMAP_CACHE";
public BitmapDiskCache(Context context) {
File cacheDir = getDiskCacheDir(context);
new InitDiskCacheTask().execute(cacheDir);
}
private class InitDiskCacheTask extends AsyncTask<File, Void, Void> {
@Override
protected Void doInBackground(File... params) {
synchronized (mDiskCacheLock) {
File cacheDir = params[0];
try {
mDiskLruCache = DiskLruCache.open(cacheDir, 1, 1, DISK_CACHE_SIZE);
} catch (IOException e) {
e.printStackTrace();
}
mDiskCacheLock.notifyAll(); // Wake any waiting threads
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
mDiskCacheStarting = false; // Finished initialization
}
}
public interface DecodingCallback {
void done(Bitmap bitmap);
}
public void get(String key, DecodingCallback callback) {
new DecodingTask(callback).execute(key);
}
private class DecodingTask extends AsyncTask<String, Void, Bitmap> {
private DecodingCallback callback;
private DecodingTask(DecodingCallback callback) {
this.callback = callback;
}
// Decode image in background.
@Override
protected Bitmap doInBackground(String... params) {
final String imageKey = String.valueOf(params[0]);
DiskLruCache.Snapshot foundSnapshot = null;
synchronized (mDiskCacheLock) {
// Wait while disk cache is started from background thread
while (mDiskCacheStarting) {
try {
mDiskCacheLock.wait();
} catch (InterruptedException ignored) {
}
}
if (mDiskLruCache != null) {
try {
foundSnapshot = mDiskLruCache.get(imageKey);
} catch (Exception e) {}
}
}
if (foundSnapshot != null) try(DiskLruCache.Snapshot snapshot = foundSnapshot) {
return BitmapFactory.decodeStream(snapshot.getInputStream(0));
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
callback.done(bitmap);
}
}
public interface EncodingCallback {
void done(String key);
}
public void add(Bitmap bitmap, EncodingCallback callback) {
new EncodingTask(callback).execute(bitmap);
}
private class EncodingTask extends AsyncTask<Bitmap, Void, String> {
private EncodingCallback callback;
private EncodingTask(EncodingCallback callback) {
this.callback = callback;
}
// Encode image in background.
@Override
protected String doInBackground(Bitmap... bitmaps) {
synchronized (mDiskCacheLock) {
DiskLruCache.Editor editor = null;
try {
String key = UUID.randomUUID().toString();
if (mDiskLruCache != null && mDiskLruCache.get(key) == null) {
editor = mDiskLruCache.edit(key);
bitmaps[0].compress(Bitmap.CompressFormat.PNG, 95, editor.newOutputStream(0));
editor.commit();
return key;
}
} catch (IOException e) {
e.printStackTrace();
if (editor != null) {
try {
editor.abort();
} catch (IOException ignored) {
}
}
}
return null;
}
}
@Override
protected void onPostExecute(String key) {
callback.done(key);
}
}
// Creates a unique subdirectory of the designated app cache directory. Tries to use external
// but if not mounted, falls back on internal storage.
private static File getDiskCacheDir(Context context) {
// Check if media is mounted or storage is built-in, if so, try and use external cache dir
// otherwise use internal cache dir
final String cachePath =
Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
!isExternalStorageRemovable() ? context.getExternalCacheDir().getPath() :
context.getCacheDir().getPath();
return new File(cachePath + File.separator + DISK_CACHE_SUBDIR);
}
public void close() {
synchronized (mDiskCacheLock) {
try {
if (!mDiskLruCache.isClosed()) {
mDiskLruCache.close();
}
mDiskLruCache.delete();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}