BitmapFactory加载大尺寸资源图不显示,自定义图片加载遇问题求助
解决Android加载大尺寸图片不显示的问题
先帮你理清楚核心问题:你遇到的情况是因为系统对不同drawable文件夹下的图片会做密度缩放。默认的drawable文件夹属于mdpi密度等级,如果你的设备是xxhdpi(大部分主流手机都是),系统会把mdpi的图片放大3倍来适配屏幕——21001600的图放大后会变成63004800,这时候Bitmap的内存占用会飙升到近120MB(按ARGB_8888计算:630048004字节),虽然调试时能看到Bitmap对象存在,但GPU可能因为纹理尺寸超限或者内存不足,静默放弃渲染,所以看不到图片也没报错。移到drawable-xxhdpi后,系统不需要缩放(或缩放比例极小),内存占用回到正常的210016004≈13MB,自然能正常显示。
接下来针对两种场景给你解决方案:
一、加载资源文件夹内的大图片
除了放到对应密度文件夹,更稳妥的方式是主动对图片进行采样压缩,避免依赖系统的密度适配:
BitmapFactory.Options options = new BitmapFactory.Options(); // 先只获取图片尺寸,不加载到内存 options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.drawable.imagename, options); // 计算合适的采样率,比如目标宽高设为屏幕宽高(可根据你的需求调整) int targetWidth = getResources().getDisplayMetrics().widthPixels; int targetHeight = getResources().getDisplayMetrics().heightPixels; int inSampleSize = calculateInSampleSize(options, targetWidth, targetHeight); // 加载压缩后的图片 options.inJustDecodeBounds = false; options.inSampleSize = inSampleSize; // 可选:设置图片格式降低内存,比如RGB_565比ARGB_8888省一半内存 options.inPreferredConfig = Bitmap.Config.RGB_565; Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.imagename, options);
这里的calculateInSampleSize方法可以这么写:
private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { 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; // 找到最大的inSampleSize,使得采样后的宽高仍大于等于目标宽高 while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
二、处理用户从相册选择的自定义图片
相册里的图片通常尺寸更大(比如手机拍照的4000*3000甚至更高),直接加载肯定会出问题,必须用采样压缩的方式处理,步骤如下:
- 从相册选择图片后,拿到图片的Uri,先获取图片的真实宽高:
// 假设你已经拿到了相册图片的Uri Uri imageUri = ...; BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // 通过Uri获取输入流来解码尺寸 try (InputStream is = getContentResolver().openInputStream(imageUri)) { BitmapFactory.decodeStream(is, null, options); } catch (IOException e) { e.printStackTrace(); }
- 同样用上面的
calculateInSampleSize计算采样率,然后加载压缩后的图片:
options.inJustDecodeBounds = false; options.inSampleSize = calculateInSampleSize(options, targetWidth, targetHeight); options.inPreferredConfig = Bitmap.Config.RGB_565; try (InputStream is = getContentResolver().openInputStream(imageUri)) { Bitmap customBmp = BitmapFactory.decodeStream(is, null, options); // 把Bitmap设置到ImageView显示 imageView.setImageBitmap(customBmp); } catch (IOException e) { e.printStackTrace(); }
额外提醒:加载大图片后,记得在不需要显示的时候及时释放Bitmap资源(比如在Activity的onDestroy或者Fragment的onDestroyView中调用bmp.recycle(),并置为null),避免内存泄漏。
内容的提问来源于stack exchange,提问作者ingo
相关产品推荐
相关产品推荐

