我是所有内存管理主题的新手,所以有很多事情我不理解
我正试图在我的应用程序中缓存图像,但它的内存消耗问题:
所有的位图Chaching代码几乎都是从这里复制粘贴的:http://developer.android.com/training/displaying-bitmaps/index.html
我在eclipse的DDMS视图中调试了代码并检查了堆大小,在这些代码行之后大约有15mb的跳转:
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
在"decodeSampledBitmapFromResource"方法中。
图像为1024x80075kb的jpg文件。根据我在互联网上已经看到的,这张图像应该占用的内存量大约是1024*800*4(每像素字节数)=3.125mb
所有关于这个主题的线索都没有说明为什么它占用了比它应该占用的更多的内存。有没有一种方法可以用合理的内存缓存一个图像?
编辑
我尝试使用下面@ArshadParwez的答案中建议的decodeFile方法。使用这种方法,在BitmapFactory.decodeStream方法之后,内存只增加了3.5mb——问题已经解决了,但我想直接从资源中缓存位图。
我注意到,在decodeResource方法中,有两个内存"跳跃"——一个大约是3.5mb——这是合理的,另一个是14mb的奇怪跳跃。这些14mb是用来做什么的?为什么会发生这种情况?
图像也根据密度进行缩放,因此它们可以使用大量内存。
例如,如果图像文件位于drawable
文件夹(即mdpi
密度)中,并且在xhdpi
设备上运行,则宽度和高度都将加倍。也许这个链接可以帮助您,或者这一个。
因此,在您的示例中,图像文件将占用的字节为:
(1024*2)*(800*2)*4=13107200字节。
如果你在xxhdpi
设备上运行它(比如HTC和Galaxy S4),情况会更糟。
你能做什么?将图像文件放在正确的密度文件夹(drawable-xhdpi
或drawable-xxhdpi
)中,或放在drawable-nodpi
(或assets文件夹)中,然后根据需要缩小图像。
顺便说一句,你不必设置options.inJustDecodeBounds = false
,因为它是默认行为。事实上,您可以为位图选项设置null。
关于缩小规模,您可以使用谷歌的方式或我的方式每种方式都有自己的优点和缺点。
关于缓存有很多方法,最常见的是LRU缓存。我最近还创建了一个替代方案(链接此处或此处),它允许您缓存更多的图像并避免OOM,但它给了您很大的责任。
您可以使用此方法传递图像并从中获取位图:
public Bitmap decodeFile(File f) {
Bitmap b = null;
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream fis = new FileInputStream(f);
BitmapFactory.decodeStream(fis, null, o);
fis.close();
int IMAGE_MAX_SIZE = 1000;
int scale = 1;
if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
scale = (int) Math.pow(
2,
(int) Math.round(Math.log(IMAGE_MAX_SIZE
/ (double) Math.max(o.outHeight, o.outWidth))
/ Math.log(0.5)));
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
fis = new FileInputStream(f);
b = BitmapFactory.decodeStream(fis, null, o2);
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
return b;
}
@Ori Wasserman:根据您的请求,我使用了一种方法从资源文件夹中获取图像,我也使用了一个7MB的图像。我把7MB的图像放在"res->drawable"文件夹中,使用以下代码,它没有崩溃,图像显示在imageview中:
Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.image_7mb);
loBitmap = Bitmap.createScaledBitmap(image, width_of_screen , height_of_screen, true);
imageview.setImageBitmap(loBitmap);