Android应用选取相册中相机拍摄的图片时崩溃,该如何解决?
崩溃核心原因分析
按出现概率从高到低排序:
- 最常见原因是内存溢出(OOM):手机相机拍摄的原图分辨率普遍很高(多为4000万像素及以上),直接使用
MediaStore.Images.Media.getBitmap加载完整原图,ARGB_8888格式下一张4000*3000分辨率的图片会占用48MB内存,很容易超出应用内存阈值触发崩溃,而普通相册图片/截图分辨率低,内存占用小所以运行正常。 - 第二个常见原因是权限适配缺失:
- Android 6.0及以上系统,存储类权限需要动态申请用户授权,仅在Manifest静态声明不生效
- Android 13(API 33)及以上系统,原有
READ_EXTERNAL_STORAGE权限已废弃,替换为READ_MEDIA_IMAGES权限,未适配会导致读取图片异常
- 小概率为分区存储适配问题:Android 10及以上开启分区存储后,直接操作图片文件路径会触发权限错误,但你当前使用URI读取的写法本身是合规的,出现概率较低。
修复方案
1. 新增图片采样压缩逻辑,避免加载完整原图
替换原有getBitmap逻辑,先读取图片尺寸,按你的ImageView尺寸计算采样率,加载缩放后的位图,示例代码如下:
// 工具方法:从URI加载缩放后的位图 public Bitmap getScaledBitmapFromUri(Context context, Uri uri, int targetWidth, int targetHeight) throws IOException { ContentResolver resolver = context.getContentResolver(); // 第一步:仅读取图片尺寸,不加载整张图到内存 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; InputStream inputStream = resolver.openInputStream(uri); BitmapFactory.decodeStream(inputStream, null, options); inputStream.close(); // 计算采样率 int width = options.outWidth; int height = options.outHeight; int inSampleSize = 1; if (height > targetHeight || width > targetWidth) { int halfHeight = height / 2; int halfWidth = width / 2; while ((halfHeight / inSampleSize) >= targetHeight && (halfWidth / inSampleSize) >= targetWidth) { inSampleSize *= 2; } } // 第二步:按采样率加载缩放后的位图 options.inJustDecodeBounds = false; options.inSampleSize = inSampleSize; options.inPreferredConfig = Bitmap.Config.RGB_565; // 不需要透明度的话用这个格式,内存占用减少一半 InputStream scaledInputStream = resolver.openInputStream(uri); Bitmap bitmap = BitmapFactory.decodeStream(scaledInputStream, null, options); scaledInputStream.close(); return bitmap; }
调用的时候传入你的ImageView的宽高即可:
// onActivityResult里替换原有getBitmap逻辑 bitmap = getScaledBitmapFromUri(this, selectedImage, imageView.getWidth(), imageView.getHeight());
2. 补全权限适配
在Manifest中更新权限声明:
<!-- 相机权限 --> <uses-permission android:name="android.permission.CAMERA"/> <!-- Android 12及以下读取存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 13及以上读取图片权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
同时补充动态权限申请逻辑,用户授权后再调用选图方法。
3. 补充异常捕获
可以在现有catch块中新增OutOfMemoryError捕获,避免直接崩溃:
catch (OutOfMemoryError e) { e.printStackTrace(); Toast.makeText(this, "图片加载失败,内存不足", Toast.LENGTH_SHORT).show(); }
内容的提问来源于stack exchange,提问作者Lindalee
相关产品推荐
相关产品推荐

