You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Activity Result API从图库获取多图时触发java.lang.OutOfMemoryError,如何压缩图片?

解决Activity Result API选择多张图片时的OutOfMemoryError问题

这个问题确实很常见——直接加载高分辨率的原图很容易把内存撑爆,尤其是一次性加载多张的时候。咱们可以通过图片采样压缩来解决,在把图片显示到ImageView之前先缩小它的尺寸,减少内存占用。下面是具体的修改方案:

1. 编写图片压缩工具方法

首先添加一个用于从Uri获取压缩后Bitmap的工具方法,利用BitmapFactory.Options的inSampleSize参数来降低图片分辨率:

private Bitmap getResizedBitmapFromUri(Context context, Uri uri, int targetWidth, int targetHeight) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    // 先只获取图片的宽高信息,不加载整个Bitmap到内存
    options.inJustDecodeBounds = true;
    
    try {
        InputStream inputStream = context.getContentResolver().openInputStream(uri);
        BitmapFactory.decodeStream(inputStream, null, options);
        inputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }

    // 计算合适的采样率:把图片宽高缩小到目标尺寸以内
    int width = options.outWidth;
    int height = options.outHeight;
    int inSampleSize = 1;

    if (height > targetHeight || width > targetWidth) {
        final int halfHeight = height / 2;
        final int halfWidth = width / 2;
        // 找到最大的inSampleSize,使得缩小后的图片宽高仍大于等于目标尺寸
        while ((halfHeight / inSampleSize) >= targetHeight
                && (halfWidth / inSampleSize) >= targetWidth) {
            inSampleSize *= 2;
        }
    }

    // 现在加载压缩后的Bitmap
    options.inJustDecodeBounds = false;
    options.inSampleSize = inSampleSize;
    options.inPreferredConfig = Bitmap.Config.RGB_565; // 进一步减少内存占用(每个像素2字节,ARGB_8888是4字节)

    try {
        InputStream inputStream = context.getContentResolver().openInputStream(uri);
        Bitmap resizedBitmap = BitmapFactory.decodeStream(inputStream, null, options);
        inputStream.close();
        return resizedBitmap;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

2. 修改Activity Result回调逻辑

在onActivityResult中,不再直接用setImageURI加载原图,而是调用上面的压缩方法获取小尺寸Bitmap后再设置给ImageView:

ActivityResultLauncher<String> launchImage= registerForActivityResult(
    new ActivityResultContracts.GetMultipleContents(),
    new ActivityResultCallback<List<Uri>>() {
        @Override
        public void onActivityResult(List<Uri> uriList) {
            try {
                // 定义目标ImageView的尺寸(和你设置的LayoutParams一致:600x800)
                final int targetWidth = 600;
                final int targetHeight = 800;
                
                for (Uri uri : uriList) {
                    ImageView imageView = new ImageView(MainActivity.this);
                    LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(targetWidth, targetHeight);
                    lp.setMargins(0, 50, 0, 0);
                    imageView.setLayoutParams(lp);
                    
                    // 获取压缩后的Bitmap
                    Bitmap resizedBitmap = getResizedBitmapFromUri(MainActivity.this, uri, targetWidth, targetHeight);
                    if (resizedBitmap != null) {
                        imageView.setImageBitmap(resizedBitmap);
                    } else {
                        // 加载失败时的 fallback,比如显示默认占位图
                        imageView.setImageResource(R.drawable.default_image);
                    }
                    ll.addView(imageView);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });

3. 额外优化建议

  • 使用图片加载库:如果不想自己处理压缩和内存管理,推荐用Glide、Picasso这类成熟的图片加载库,它们会自动处理图片压缩、内存缓存、磁盘缓存,代码更简洁:
    比如用Glide的话,只需要一行代码:
    Glide.with(MainActivity.this)
         .load(uri)
         .override(600, 800) // 指定目标尺寸
         .into(imageView);
    
  • 回收Bitmap:如果Activity销毁或者不再需要这些图片时,可以遍历ImageView回收Bitmap,避免内存泄漏:
    @Override
    protected void onDestroy() {
        super.onDestroy();
        for (int i = 0; i < ll.getChildCount(); i++) {
            View child = ll.getChildAt(i);
            if (child instanceof ImageView) {
                Bitmap bitmap = ((ImageView) child).getDrawingCache();
                if (bitmap != null && !bitmap.isRecycled()) {
                    bitmap.recycle();
                }
            }
        }
    }
    

内容的提问来源于stack exchange,提问作者steady blaze

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 13:28:14