我正在构建一个Android应用程序,其中每个实体都有一个代表其精灵的位图。但是,每个实体都可以复制(例如,可能有3个实体asdf副本)。
一种方法是预先加载所有sprite,然后将正确的sprite放在实体的构造函数中。
但是,我想懒惰地解码位图,以便实体的构造函数将解码位图。唯一的问题是重复的实体将使用2倍的内存加载相同的位图两次(如果实体创建n次,则加载n次)。
为了解决这个问题,我构建了一个SingularBitmapFactory,它将一个已解码的Bitmap存储到一个哈希中,如果再次询问相同的位图,则只返回先前的哈希值,而不是构建一个新的。但问题是,工厂持有所有位图的副本,因此不会收集垃圾。
将hashmap切换为弱引用值的最佳方法是什么?换句话说,我想要一个结构,如果任何其他对象持有对它的引用,那么值将不会是GC,但只要没有其他对象引用它,那么它就可以是GC。
答案 0 :(得分:11)
你所说的几乎 - 使Bitmap(地图的对象面)成为WeakReference而不是Bitmap。然后,您必须添加额外的检查以查看引用在将其传递回实体之前是否仍然有效。这是一般概念的快速草图。
public class SingularBitmapFactory {
private HashMap <String, WeakReference<Bitmap>> cache = new HashMap<String, WeakReference<Bitmap>>();
public Bitmap getBitmap(String key) {
Bitmap image = null;
WeakReference<Bitmap> ref = cache.get(key);
if(ref != null) {
image = ref.get();
}
if(image == null) {
// Load image here ...
cache.put(key, new WeakReference<Bitmap>(image));
}
return image;
}
}
答案 1 :(得分:7)
老问题,但今天我需要这个,基于@ iagreen的答案,我已经概括了这个想法,也许它对某人来说很方便......
public static class WeakValueHashMap<K,V> {
private HashMap<K,WeakReference<V>> mDatabase=new HashMap<K, WeakReference<V>>();
public V get(K key) {
WeakReference<V> weakRef=mDatabase.get(key);
if (weakRef==null) return null;
V result=weakRef.get();
if (result==null) {
// edge case where the key exists but the object has been garbage collected
// we remove the key from the table, because tables are slower the more
// keys they have (@kisp's comment)
mDatabase.remove(key);
}
return result;
}
public void put(K key, V value) {
mDatabase.put(key, new WeakReference<V>(value));
}
}
所以你可以做例如
private WeakValueHashMap<String,Drawable> mTextDrawables=new WeakValueHashMap<String,Drawable>();
并且Drawables将与Weakreferences
一起存储。
方法“containsValue”实现起来比较棘手,你必须迭代并取消引用所有的WeakRefs ...
答案 2 :(得分:-3)
最好的方法是使用WeakHashMap类,它为您完成所有工作,并且不需要对代码进行任何更改。这里有一个非常好的教程:http://weblogs.java.net/blog/2006/05/04/understanding-weak-references 它相当古老但仍然没问题。 WeakHashMap存储对密钥的弱引用很重要。这意味着你不能只使用常量字符串值作为键,而是使用像Integer这样的东西,并将它作为弱引用存储在常量类中。