我想知道是否有人在架构中有任何经验,这些架构旨在动态发现尽可能多的图像。
在我的情况下,我为从ListView点击的每个项目请求一个Bitmap。这些位图是通过网络接收的(在处理或网络I / O方面不是便宜的操作)。用户可能会从列表中加载一些项目,在它们之间切换。我缓存这些图像,以便后续的项目请求将导致立即加载位图:
private Bitmap bitmap = null;
public Bitmap getBitmap(int id) {
if(bitmap == null) bitmap = expensiveNetworkOperationToGetBitmap(id);
return bitmap;
}
(请忽略线程阻止问题)
但是,用户完全可以浏览很多项目。每个人慢慢占用一块内存,最终超出预算并崩溃应用程序。
这让我提出了一个问题:是否可以动态检测缓存何时达到限制?如果是这样,应该可以在添加新图像时开始销毁旧图像。请参阅下面的示例代码:
private HashMap<Integer, Bitmap> bitmaps = new HashMap<Integer, Bitmap>();
public Bitmap getBitmap(int id) {
Bitmap bitmap;
if(!bitmaps.contains(id)) {
if(// Bitmap budget close to being exeeded?) {
bitmaps.keyValues().get(0).recycle();
bitmaps.remove(bitmaps.keyValues().get(0));
}
bitmap = expensiveNetworkOperationToGetBitmap(id);
bitmaps.put(id, bitmap);
else {
bitmap = bitmaps.get(id);
}
return bitmap;
}
再次请忽略对从HashMap弹出第一个Bitmap的无效性的担忧。
我希望有人对已注释的部分提出建议。如果有一个比这更好的解决方案那么听起来很棒。
答案 0 :(得分:1)
您无法检测到达到堆的限制(在运行时AFAIK无法获得占用堆的大小)
这就是我的所作所为。
我有一个listView并检测随时显示的图像数量(可见行|列)。添加新位图后,我会检查适配器,任何imageview都不会显示哪些缓存图像。如果我找到一个或多个i .recycle()它们。当我需要重新加载图像(我已经存储到手机的内存缓存)时,我不仅检查缓存中是否存在该图像,还检查位图是否被回收。 如果是再循环我重新编码它,否则如果没有我再次下载它。 这是最安全的操作。我还根据显示的位置缩小图像比例。 例如,如果我有200x200的图像,而imageView只有20x20,那么我会将图像缩小10次。
这样android会处理我在其上显示的evey单个图像。这就是回收位图,以及android回收imageViews本身的保存方式。
您必须知道当前有多少位图可见,以便您回收其余位图。
另外一个方便的技巧是当您对图像进行编码时(首先必须将其下载到缓存中)使用fileDescriptor进行编码
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
o2.inPurgeable = true;
o2.inTempStorage = new byte[16 * 1024];
o2.inDither = true;
o2.inInputShareable = true;
FileInputStream fs = null;
try {
fs = new FileInputStream(f);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if (fs != null) {
Bitmap b = BitmapFactory.decodeFileDescriptor(fs.getFD(),null, o2);
}
但如果你做的一切都正确,你就不需要fileDescriptor(谁比较慢)
答案 1 :(得分:1)
如果您希望能够让缓存增长基本上无限制地达到VM堆的限制,您可以使用像SoftReference集合这样的东西到位图。
http://developer.android.com/reference/java/lang/ref/SoftReference.html
您可能还希望在活动onLowMemory()中实现,以便在您希望拥有如此大的缓存时也能很好地使用系统。