Skip to content

Commit 6248896

Browse files
committed
add memory cache and image loader
1 parent b1235cc commit 6248896

File tree

2 files changed

+212
-0
lines changed

2 files changed

+212
-0
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package info.anodsplace.android.cache;
2+
3+
import android.graphics.Bitmap;
4+
import android.util.Log;
5+
6+
import java.util.Collections;
7+
import java.util.Iterator;
8+
import java.util.LinkedHashMap;
9+
import java.util.Map;
10+
import java.util.Map.Entry;
11+
12+
public class MemoryCache {
13+
14+
private static final String TAG = "MemoryCache";
15+
16+
private Map<String, Bitmap> cache = Collections.synchronizedMap(
17+
new LinkedHashMap<String, Bitmap>(10, 1.5f, true));//Last argument true for LRU ordering
18+
19+
private long size = 0;//current allocated size
20+
21+
private long limit = 1000000;//max memory in bytes
22+
23+
public MemoryCache() {
24+
//use 25% of available heap size
25+
setLimit(Runtime.getRuntime().maxMemory() / 4);
26+
}
27+
28+
public void setLimit(long new_limit) {
29+
limit = new_limit;
30+
Log.i(TAG, "MemoryCache will use up to " + limit / 1024. / 1024. + "MB");
31+
}
32+
33+
public Bitmap get(String id) {
34+
if (!cache.containsKey(id)) {
35+
return null;
36+
}
37+
return cache.get(id);
38+
}
39+
40+
public void put(String id, Bitmap bitmap) {
41+
try {
42+
if (cache.containsKey(id)) {
43+
size -= getSizeInBytes(cache.get(id));
44+
}
45+
cache.put(id, bitmap);
46+
size += getSizeInBytes(bitmap);
47+
checkSize();
48+
} catch (Throwable th) {
49+
th.printStackTrace();
50+
}
51+
}
52+
53+
private void checkSize() {
54+
Log.i(TAG, "cache size=" + size + " length=" + cache.size());
55+
if (size > limit) {
56+
Iterator<Entry<String, Bitmap>> iter = cache.entrySet()
57+
.iterator();//least recently accessed item will be the first one iterated
58+
while (iter.hasNext()) {
59+
Entry<String, Bitmap> entry = iter.next();
60+
size -= getSizeInBytes(entry.getValue());
61+
iter.remove();
62+
if (size <= limit) {
63+
break;
64+
}
65+
}
66+
Log.i(TAG, "Clean cache. New size " + cache.size());
67+
}
68+
}
69+
70+
public void clear() {
71+
cache.clear();
72+
}
73+
74+
long getSizeInBytes(Bitmap bitmap) {
75+
if (bitmap == null) {
76+
return 0;
77+
}
78+
return bitmap.getRowBytes() * bitmap.getHeight();
79+
}
80+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package info.anodsplace.android.image;
2+
3+
import android.app.Activity;
4+
import android.graphics.Bitmap;
5+
import android.widget.ImageView;
6+
7+
import java.util.Collections;
8+
import java.util.Map;
9+
import java.util.WeakHashMap;
10+
import java.util.concurrent.ExecutorService;
11+
import java.util.concurrent.Executors;
12+
13+
import info.anodsplace.android.cache.MemoryCache;
14+
15+
abstract public class ImageLoader {
16+
17+
private MemoryCache mMemoryCache = new MemoryCache();
18+
19+
private Map<ImageView, String> mImageViews = Collections
20+
.synchronizedMap(new WeakHashMap<ImageView, String>());
21+
22+
private ExecutorService mExecutorService;
23+
24+
public ImageLoader() {
25+
mExecutorService = Executors.newFixedThreadPool(5);
26+
}
27+
28+
abstract protected Bitmap loadBitmap(String imgUID);
29+
30+
public Bitmap getCachedImage(String imgUID) {
31+
return mMemoryCache.get(imgUID);
32+
}
33+
34+
protected void cacheImage(String imgUID, Bitmap bmp) {
35+
mMemoryCache.put(imgUID, bmp);
36+
}
37+
38+
public void releaseImageView(ImageView imageView) {
39+
mImageViews.remove(imageView);
40+
}
41+
42+
public void loadImage(String imgUID, ImageView imageView) {
43+
mImageViews.put(imageView, imgUID);
44+
Bitmap bitmap = mMemoryCache.get(imgUID);
45+
if (bitmap != null) {
46+
imageView.setImageBitmap(bitmap);
47+
} else {
48+
queuePhoto(imgUID, imageView);
49+
}
50+
}
51+
52+
private void queuePhoto(String imgUID, ImageView imageView) {
53+
PhotoToLoad p = new PhotoToLoad(imgUID, imageView);
54+
mExecutorService.submit(new PhotosLoader(p));
55+
}
56+
57+
//Task for the queue
58+
private class PhotoToLoad {
59+
60+
public String imgUID;
61+
62+
public ImageView imageView;
63+
64+
public PhotoToLoad(String u, ImageView i) {
65+
imgUID = u;
66+
imageView = i;
67+
}
68+
}
69+
70+
class PhotosLoader implements Runnable {
71+
72+
PhotoToLoad mPhotoToLoad;
73+
74+
PhotosLoader(PhotoToLoad photoToLoad) {
75+
mPhotoToLoad = photoToLoad;
76+
}
77+
78+
@Override
79+
public void run() {
80+
if (imageViewReused(mPhotoToLoad)) {
81+
return;
82+
}
83+
Bitmap bmp = loadBitmap(mPhotoToLoad.imgUID);
84+
cacheImage(mPhotoToLoad.imgUID, bmp);
85+
if (imageViewReused(mPhotoToLoad)) {
86+
return;
87+
}
88+
Activity a = (Activity) mPhotoToLoad.imageView.getContext();
89+
if (bmp == null) {
90+
mImageViews.remove(mPhotoToLoad.imageView);
91+
return;
92+
}
93+
BitmapDisplayer bd = new BitmapDisplayer(bmp, mPhotoToLoad);
94+
a.runOnUiThread(bd);
95+
}
96+
}
97+
98+
boolean imageViewReused(PhotoToLoad photoToLoad) {
99+
String tag = mImageViews.get(photoToLoad.imageView);
100+
if (tag == null || !tag.equals(photoToLoad.imgUID)) {
101+
return true;
102+
}
103+
return false;
104+
}
105+
106+
//Used to display mBitmap in the UI thread
107+
class BitmapDisplayer implements Runnable {
108+
109+
Bitmap mBitmap;
110+
111+
PhotoToLoad mPhotoToLoad;
112+
113+
public BitmapDisplayer(Bitmap b, PhotoToLoad p) {
114+
mBitmap = b;
115+
mPhotoToLoad = p;
116+
}
117+
118+
public void run() {
119+
if (imageViewReused(mPhotoToLoad)) {
120+
return;
121+
}
122+
if (mBitmap != null) {
123+
mPhotoToLoad.imageView.setImageBitmap(mBitmap);
124+
}
125+
}
126+
}
127+
128+
public void clearCache() {
129+
mMemoryCache.clear();
130+
}
131+
132+
}

0 commit comments

Comments
 (0)