Android 从Uri加载位图时出现内存不足错误
我使用以下方法从Android 从Uri加载位图时出现内存不足错误,android,bitmap,Android,Bitmap,我使用以下方法从Uri获取位图: private static Bitmap getBitmapFromUri(@NonNull Context context, @NonNull Uri uri) throws IOException { ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
Uri
获取位图
:
private static Bitmap getBitmapFromUri(@NonNull Context context, @NonNull Uri uri) throws IOException {
ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(uri, "r");
assert parcelFileDescriptor != null;
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return image;
}
问题是,我有时在Crashlytics
的return语句中遇到OOM错误。我认为这是因为所选图像的大小较大。如何修改它以返回最佳质量的位图缩小版本,从而不会导致内存不足错误
编辑我自己发布了一个答案。请看一看,让我知道这是正确的方法。解码前,您必须调整图像大小。这是我解码图像并在图像视图中显示它的代码
private void loadImage(Uri u, String path) {
try {
ContentResolver cr = context.getContentResolver();
InputStream in;
in = cr.openInputStream(u);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, o);
in.close();
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)));
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
in = cr.openInputStream(u);
Bitmap bitmap = BitmapFactory.decodeStream(in, null, o2);
in.close();
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), getRotation(path), true);
int nh = (int) ( rotatedBitmap.getHeight() * (512.0 / rotatedBitmap.getWidth()) );
Bitmap scaled = Bitmap.createScaledBitmap(rotatedBitmap, 512, nh, true);
String pathTest = MediaStore.Images.Media.insertImage(context.getContentResolver(), scaled, "Title", null);
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(Uri.decode(Uri.parse(pathTest).toString()), mPicture, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
mPicture.setImageBitmap(loadedImage);
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
}
});
} catch (Exception e) {
//Toast.makeText(context, context.getString(R.string.fail_to_load_image), Toast.LENGTH_SHORT).show();
Log.e("TAG", e.toString());
}
}
private Matrix getRotation(String pathPetPicture) {
Matrix matrix = new Matrix();
try {
ExifInterface exif = new ExifInterface(pathPetPicture);
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
switch (rotation) {
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
matrix.setScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.setRotate(180);
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
matrix.setRotate(180);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
matrix.setRotate(90);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.setRotate(90);
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
matrix.setRotate(-90);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
matrix.setRotate(-90);
break;
case ExifInterface.ORIENTATION_NORMAL:
default:
break;
}
} catch (Exception e) {
Log.e("TAG", e.toString());
}
return matrix;
}
在解码之前,您必须调整图像的大小。这是我解码图像并在图像视图中显示它的代码
private void loadImage(Uri u, String path) {
try {
ContentResolver cr = context.getContentResolver();
InputStream in;
in = cr.openInputStream(u);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, o);
in.close();
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)));
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
in = cr.openInputStream(u);
Bitmap bitmap = BitmapFactory.decodeStream(in, null, o2);
in.close();
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), getRotation(path), true);
int nh = (int) ( rotatedBitmap.getHeight() * (512.0 / rotatedBitmap.getWidth()) );
Bitmap scaled = Bitmap.createScaledBitmap(rotatedBitmap, 512, nh, true);
String pathTest = MediaStore.Images.Media.insertImage(context.getContentResolver(), scaled, "Title", null);
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(Uri.decode(Uri.parse(pathTest).toString()), mPicture, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
mPicture.setImageBitmap(loadedImage);
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
}
});
} catch (Exception e) {
//Toast.makeText(context, context.getString(R.string.fail_to_load_image), Toast.LENGTH_SHORT).show();
Log.e("TAG", e.toString());
}
}
private Matrix getRotation(String pathPetPicture) {
Matrix matrix = new Matrix();
try {
ExifInterface exif = new ExifInterface(pathPetPicture);
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
switch (rotation) {
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
matrix.setScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.setRotate(180);
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
matrix.setRotate(180);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
matrix.setRotate(90);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.setRotate(90);
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
matrix.setRotate(-90);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
matrix.setRotate(-90);
break;
case ExifInterface.ORIENTATION_NORMAL:
default:
break;
}
} catch (Exception e) {
Log.e("TAG", e.toString());
}
return matrix;
}
在getBitmapFromUri()中使用此选项并将代码替换为此选项
在getBitmapFromUri()中使用此选项并将代码替换为此选项。尝试以下操作
// decode image
public Bitmap decodeFile(String filePath) {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 1024;
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
bitmap = BitmapFactory.decodeFile(filePath, o2);
return bitmap;
}
//解码图像
公共位图解码文件(字符串文件路径){
//解码图像大小
BitmapFactory.Options o=新的BitmapFactory.Options();
o、 inJustDecodeBounds=true;
解码文件(文件路径,o);
//我们要扩展到的新尺寸
所需的最终int_SIZE=1024;
//找到正确的刻度值。它应该是2的幂。
内部宽度=o.向外宽度,高度=o.向外高度;
int标度=1;
while(true){
如果(宽度\u tmp<要求的\u尺寸和高度\u tmp<要求的\u尺寸)
打破
宽度_tmp/=2;
高度_tmp/=2;
比例*=2;
}
//用inSampleSize解码
BitmapFactory.Options o2=新的BitmapFactory.Options();
o2.inSampleSize=刻度;
位图=BitmapFactory.decodeFile(文件路径,o2);
返回位图;
}
愿它有帮助
如果您想高效加载大型位图,请按照以下方法操作
// decode image
public Bitmap decodeFile(String filePath) {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 1024;
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
bitmap = BitmapFactory.decodeFile(filePath, o2);
return bitmap;
}
//解码图像
公共位图解码文件(字符串文件路径){
//解码图像大小
BitmapFactory.Options o=新的BitmapFactory.Options();
o、 inJustDecodeBounds=true;
解码文件(文件路径,o);
//我们要扩展到的新尺寸
所需的最终int_SIZE=1024;
//找到正确的刻度值。它应该是2的幂。
内部宽度=o.向外宽度,高度=o.向外高度;
int标度=1;
while(true){
如果(宽度\u tmp<要求的\u尺寸和高度\u tmp<要求的\u尺寸)
打破
宽度_tmp/=2;
高度_tmp/=2;
比例*=2;
}
//用inSampleSize解码
BitmapFactory.Options o2=新的BitmapFactory.Options();
o2.inSampleSize=刻度;
位图=BitmapFactory.decodeFile(文件路径,o2);
返回位图;
}
愿它有帮助
如果您希望高效加载大型位图,请遵循使用或库:
用本地文件夹路径或服务器url替换路径
Glide.with (context).load (path).asBitmap().into(imageView);
使用或库:
用本地文件夹路径或服务器url替换路径
Glide.with (context).load (path).asBitmap().into(imageView);
我读了所有的答案,这就是我打算做的,告诉我它是否有效。在我的
应用程序
类中,在onCreate()
中,我将设备宽度和高度以像素为单位存储在共享参考
中。在修改后的代码中,我根据设备像素缩放位图。希望这能避免我犯错误
private static Bitmap getBitmapFromUri(@NonNull Context context, @NonNull Uri uri) throws IOException {
ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(uri, "r");
assert parcelFileDescriptor != null;
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
TinyDB tinyDB = new TinyDB(context);
int maxSize = Math.min(tinyDB.getInt(AppConstants.DEVICE_WIDTH, 720), tinyDB.getInt(AppConstants.DEVICE_HEIGHT, 1080));
int outWidth;
int outHeight;
int inWidth = image.getWidth();
int inHeight = image.getHeight();
if(inWidth > inHeight){
outWidth = maxSize;
outHeight = (inHeight * maxSize) / inWidth;
} else {
outHeight = maxSize;
outWidth = (inWidth * maxSize) / inHeight;
}
return Bitmap.createScaledBitmap(image, outWidth, outHeight, false);
}
我读了所有的答案,这就是我打算做的,告诉我它是否有效。在我的
应用程序
类中,在onCreate()
中,我将设备宽度和高度以像素为单位存储在共享参考
中。在修改后的代码中,我根据设备像素缩放位图。希望这能避免我犯错误
private static Bitmap getBitmapFromUri(@NonNull Context context, @NonNull Uri uri) throws IOException {
ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(uri, "r");
assert parcelFileDescriptor != null;
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
TinyDB tinyDB = new TinyDB(context);
int maxSize = Math.min(tinyDB.getInt(AppConstants.DEVICE_WIDTH, 720), tinyDB.getInt(AppConstants.DEVICE_HEIGHT, 1080));
int outWidth;
int outHeight;
int inWidth = image.getWidth();
int inHeight = image.getHeight();
if(inWidth > inHeight){
outWidth = maxSize;
outHeight = (inHeight * maxSize) / inWidth;
} else {
outHeight = maxSize;
outWidth = (inWidth * maxSize) / inHeight;
}
return Bitmap.createScaledBitmap(image, outWidth, outHeight, false);
}
同时发布decodeFileDescriptor()方法。向下采样图像。签出这个链接@saurabhgupta我还没有写这个函数。它是内置的。我在Android文档中发现了这种方法。如果位图会出现OOM错误,我只需要修改它以获得最佳的位图缩小版本。@AmitTiwari…请参阅我的回答,同时发布decodeFileDescriptor()方法。向下采样您的图像。签出这个链接@saurabhgupta我还没有写这个函数。它是内置的。我在Android文档中发现了这种方法。如果位图将出现OOM错误,我只需要修改它以获得最佳的位图缩小版本。@Amittwari…请参阅我的回答我不想硬编码任何值,如100。我希望它是最好的质量,这样它就不会溢出内存。我该怎么做呢?这张图片是来自URL吗?如果是的话,不要创建位图,只要用毕加索来显示它就不会重新调整大小了,我知道。但图像是从手机的多媒体资料中加载的。我不想硬编码任何值,比如100。我希望它是最好的质量,这样它就不会溢出内存。我该怎么做呢?这张图片是来自URL吗?如果是的话,不要创建位图,只要用毕加索来显示它就不会重新调整大小了,我知道。但图像正在从手机的多媒体资料中加载。您的解决方案很好。但我只是不想硬编码所需的大小。我希望它是动态确定的。有办法吗?因为所需的_大小可能不会在高端手机上提供OOM,但在低端手机上可能会提供OOM。您的解决方案很好。但我只是不想硬编码所需的大小。我希望它是动态确定的。有办法吗?因为所需的大小可能不会在高端手机上提供OOM,但在低端手机上可能会提供OOM。如何确定图像的最大大小?通常它与图像视图的高度相对应