大位图内存不足异常
outofmemory exception for Large Bitmap
我找到了很多关于如何加载大位图和避免内存不足异常的文档。但问题是我必须从我的 MediaStore.Images.media 中获取图像,所以经典的
google 文档中指出的 decodeFile(path,options)
对我不起作用
正如您在下面看到的,我对行 // Bitmap photo= Mediastore.Images
进行了注释,这是触发内存不足的行。在另一边添加
Bitmap bm=BitmapFactory.decodeFile(selectedImageToUri,options)
returns null
行,尽管编译器可以看到 selectedImageToUri
中的路径(表示图片所在的内容提供者)而不是选项值,即我设置为8,因为我想缩小所有图像
我的问题是如何在 bm 中插入引用用户在图库中选择的图像的位图。在行 BitMap photo
does not return null 并且工作得很好,但我取消了评论,因为在我更改了几张图片后出现内存不足异常。
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable final Bundle savedInstanceState) {
if (flagVariable) {
if (selectedImageToUri != null) {
// BitMap photo = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), Uri.parse(selectedImageToUri));
final BitmapFactory.Options options= new BitmapFactory.Options();
options.inSampleSize=8;
Bitmap bm = BitmapFactory.decodeFile(selectedImageToUri, options);
pic = new BitmapDrawable(bm);
getActivity().getWindow().setBackgroundDrawable(pic);
} else {
getDefaultImageBackground(inflater, container);
}
hiddenList = inflater.inflate(R.layout.fragment_as_list_layout_temp, container, false);
} else {
getDefaultImageBackground(inflater, container);
}
listView = (ListView) hiddenList.findViewById(R.id.list_hidden);
MediaStore.getBitmap
只是一个简单的方便方法,它看起来像这样:
public static final Bitmap getBitmap(ContentResolver cr, Uri url)
throws FileNotFoundException, IOException {
InputStream input = cr.openInputStream(url);
Bitmap bitmap = BitmapFactory.decodeStream(input);
input.close();
return bitmap;
}
您可以基于此创建自己的方法,该方法采用 options
并在 BitmapFactory
上调用不同的重载:
public static final Bitmap getBitmap(ContentResolver cr,
Uri url,
BitmapFactory.Options options)
throws FileNotFoundException, IOException {
InputStream input = cr.openInputStream(url);
Bitmap bitmap = BitmapFactory.decodeStream(input, null, options);
input.close();
return bitmap;
}
用法:
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap bm = getBitmap(getActivity().getContentResolver(),
Uri.parse(selectedImageToUri),
options);
我在这个问题上花了很多时间,但没有人给我确切的答案,最后我解决了。首先创建方法并提供图像 URI 作为参数,这将 return 位图基本上在这里我计算图像大小的基础上,我们可以管理内存和图像并以位图形式获取精确图像。
你甚至可以显示 5000×8000 和 12MiB 图片,没有任何错误代码测试只需复制粘贴到你的 class 并享受。
使用
Bitmap mBitmap = getPhoto(MYIMAGEURI);
向方法提供URI并获取位图
Bitmap getPhoto(Uri selectedImage) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
int width = metrics.widthPixels;
Bitmap photoBitmap = null;
InputStream inputStream = null;
try {
inputStream = getContentResolver().openInputStream(selectedImage);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeStream(inputStream, null, bitmapOptions);
int imageWidth = bitmapOptions.outWidth;
int imageHeight = bitmapOptions.outHeight;
@SuppressWarnings("unused")
InputStream is = null;
try {
is = getContentResolver().openInputStream(selectedImage);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
float scale = 1.0f;
if (imageWidth < imageHeight) {
if (imageHeight > width * 1.0f) {
scale = width * 1.0f / (imageHeight * 1.0f);
}
} else {
if (imageWidth > width * 1.0f) {
scale = width * 1.0f / (imageWidth * 1.0f);
}
}
photoBitmap = decodeSampledBitmapFromResource(this,
selectedImage, (int) (imageWidth * scale),
(int) (imageHeight * scale));
return photoBitmap;
}
使用图像大小解码位图样本
public static Bitmap decodeSampledBitmapFromResource(Context context,
Uri uri, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
InputStream is = null;
try {
is = context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
BitmapFactory.decodeStream(is, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode editBitmap with inSampleSize set
options.inJustDecodeBounds = false;
InputStream inputs = null;
try {
inputs = context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return BitmapFactory.decodeStream(inputs, null, options);
}
计算样本大小
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) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height
/ (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = Math.min(heightRatio, widthRatio);
// inSampleSize = heightRatio < widthRatio ? heightRatio :
// widthRatio;
}
return inSampleSize;
}
或者可以使用 manifiest.xml
中的一行代码解决
在应用程序标签中使用此
android:largeHeap="true"
我找到了很多关于如何加载大位图和避免内存不足异常的文档。但问题是我必须从我的 MediaStore.Images.media 中获取图像,所以经典的
google 文档中指出的 decodeFile(path,options)
对我不起作用
正如您在下面看到的,我对行 // Bitmap photo= Mediastore.Images
进行了注释,这是触发内存不足的行。在另一边添加
Bitmap bm=BitmapFactory.decodeFile(selectedImageToUri,options)
returns null
行,尽管编译器可以看到 selectedImageToUri
中的路径(表示图片所在的内容提供者)而不是选项值,即我设置为8,因为我想缩小所有图像
我的问题是如何在 bm 中插入引用用户在图库中选择的图像的位图。在行 BitMap photo
does not return null 并且工作得很好,但我取消了评论,因为在我更改了几张图片后出现内存不足异常。
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable final Bundle savedInstanceState) {
if (flagVariable) {
if (selectedImageToUri != null) {
// BitMap photo = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), Uri.parse(selectedImageToUri));
final BitmapFactory.Options options= new BitmapFactory.Options();
options.inSampleSize=8;
Bitmap bm = BitmapFactory.decodeFile(selectedImageToUri, options);
pic = new BitmapDrawable(bm);
getActivity().getWindow().setBackgroundDrawable(pic);
} else {
getDefaultImageBackground(inflater, container);
}
hiddenList = inflater.inflate(R.layout.fragment_as_list_layout_temp, container, false);
} else {
getDefaultImageBackground(inflater, container);
}
listView = (ListView) hiddenList.findViewById(R.id.list_hidden);
MediaStore.getBitmap
只是一个简单的方便方法,它看起来像这样:
public static final Bitmap getBitmap(ContentResolver cr, Uri url)
throws FileNotFoundException, IOException {
InputStream input = cr.openInputStream(url);
Bitmap bitmap = BitmapFactory.decodeStream(input);
input.close();
return bitmap;
}
您可以基于此创建自己的方法,该方法采用 options
并在 BitmapFactory
上调用不同的重载:
public static final Bitmap getBitmap(ContentResolver cr,
Uri url,
BitmapFactory.Options options)
throws FileNotFoundException, IOException {
InputStream input = cr.openInputStream(url);
Bitmap bitmap = BitmapFactory.decodeStream(input, null, options);
input.close();
return bitmap;
}
用法:
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap bm = getBitmap(getActivity().getContentResolver(),
Uri.parse(selectedImageToUri),
options);
我在这个问题上花了很多时间,但没有人给我确切的答案,最后我解决了。首先创建方法并提供图像 URI 作为参数,这将 return 位图基本上在这里我计算图像大小的基础上,我们可以管理内存和图像并以位图形式获取精确图像。
你甚至可以显示 5000×8000 和 12MiB 图片,没有任何错误代码测试只需复制粘贴到你的 class 并享受。
使用
Bitmap mBitmap = getPhoto(MYIMAGEURI);
向方法提供URI并获取位图
Bitmap getPhoto(Uri selectedImage) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
int width = metrics.widthPixels;
Bitmap photoBitmap = null;
InputStream inputStream = null;
try {
inputStream = getContentResolver().openInputStream(selectedImage);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeStream(inputStream, null, bitmapOptions);
int imageWidth = bitmapOptions.outWidth;
int imageHeight = bitmapOptions.outHeight;
@SuppressWarnings("unused")
InputStream is = null;
try {
is = getContentResolver().openInputStream(selectedImage);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
float scale = 1.0f;
if (imageWidth < imageHeight) {
if (imageHeight > width * 1.0f) {
scale = width * 1.0f / (imageHeight * 1.0f);
}
} else {
if (imageWidth > width * 1.0f) {
scale = width * 1.0f / (imageWidth * 1.0f);
}
}
photoBitmap = decodeSampledBitmapFromResource(this,
selectedImage, (int) (imageWidth * scale),
(int) (imageHeight * scale));
return photoBitmap;
}
使用图像大小解码位图样本
public static Bitmap decodeSampledBitmapFromResource(Context context,
Uri uri, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
InputStream is = null;
try {
is = context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
BitmapFactory.decodeStream(is, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode editBitmap with inSampleSize set
options.inJustDecodeBounds = false;
InputStream inputs = null;
try {
inputs = context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return BitmapFactory.decodeStream(inputs, null, options);
}
计算样本大小
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) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height
/ (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = Math.min(heightRatio, widthRatio);
// inSampleSize = heightRatio < widthRatio ? heightRatio :
// widthRatio;
}
return inSampleSize;
}
或者可以使用 manifiest.xml
中的一行代码解决
在应用程序标签中使用此
android:largeHeap="true"