问题描述
我想在显示从画廊或捕捉的形式摄像机的图像ImageView
。
我开始在这个过程中获得OOM
。
所以我决定找出它是如何工作的。
所以我尝试了不同尺寸的图像,这里是观察,
我试图将19KB图像加载到ImageView
并收到以下错误消息。
无法分配带有570452空闲字节的4915212字节分配和557KB直到具有2MB映像的OOM
我无法分配具有16777120个空闲字节的31961100字节分配和29MB直到OOM
2MB
为什么19KB图像需要大约4.6MB的主内存和2MB图像需要30 MB的主内存空间?
PS:我发现很多解决方案,比如根据显示器对图像进行下采样,但没有一个解释这种行为。
1楼
理想情况下,您将使用ARGB_8888
进行位图。
这意味着对于每个像素,分配4个字节(每个字节用于A,R,G,B)。
这意味着加载1024x768图像需要1024 * 768 * 4 = 3145728 B = 3072 KB = 3 MB。
这就是使用大容量内存的原因。
以下信息来自文档: :
Bitmap.Config.ALPHA_8 - 每个像素都存储为单个半透明(alpha)通道。
Bitmap.Config.ARGB_4444 - 此字段在API级别13中已弃用。由于此配置质量较差,建议使用ARGB_8888。
Bitmap.Config.ARGB_8888 - 每个像素存储在4个字节上。
Bitmap.Config.RGB_565 - 每个像素存储在2个字节上,只有RGB通道被编码:红色以5位精度(32个可能值)存储,绿色以6位精度(64个可能值)存储,蓝色以5位精度存储。
2楼
在Android中,图像的每个像素都需要4个字节的内存。
因此,如果您使用500万像素图像创建Bitmap
,则需要大约20MB。
因此,您应计算所需的样本大小,以便在不加载完整分辨率的情况下显示图像。
即使图像文件只有19KB, Bitmap
对象也会占用更多内存。
尝试创建静态方法来计算所需的样本大小:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
然后在加载完整图像之前先检查图像的边界:
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
有关这方面的更多信息,请参阅开发人员指南: :