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

Android中读取相册大图片遇TransactionTooLargeException的Java解决方案

从相册读取大图片触发TransactionTooLargeException的解决办法

问题场景

原本使用以下代码从相册读取图片:

Intent intent = null;
intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(intent, SELECT_PICTURE);

当读取大于1MB的图片时,触发如下异常:

Uncaught exception: Error Message: java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 1132804 bytes
at android.app.ActivityClient.activityStopped(ActivityClient.java:86)
at android.app.servertransaction.PendingTransactionActions$StopInfo.run(PendingTransactionActions.java:143)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8751)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)

异常根源:

Caused by: android.os.TransactionTooLargeException: data parcel size 1132804 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(BinderProxy.java:635)
at android.app.IActivityClientController$Stub$Proxy.activityStopped(IActivityClientController.java:1358)
at android.app.ActivityClient.activityStopped(ActivityClient.java:83)
... 9 more

解决思路及代码实现

异常核心原因是:ACTION_PICK返回的Intent会把图片完整数据塞进Parcel,当图片体积超过Binder事务的默认大小限制(约1MB)时,就会触发该异常。解决关键是只获取图片Uri,再通过Uri读取并压缩图片,避免大数据量的Binder传输。

方案1:通过Uri读取并压缩图片(推荐)

保留原启动相册的逻辑,在结果回调中只拿Uri,再通过ContentResolver读取图片并压缩:

启动相册代码

private static final int SELECT_PICTURE = 100;

// 启动相册选择
public void pickImageFromGallery() {
    Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    intent.setType("image/*");
    startActivityForResult(intent, SELECT_PICTURE);
}

处理返回结果并压缩图片

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == SELECT_PICTURE && resultCode == RESULT_OK && data != null) {
        Uri imageUri = data.getData();
        if (imageUri != null) {
            // 获取压缩后的Bitmap,避免内存溢出和事务过大问题
            Bitmap compressedBitmap = getCompressedBitmapFromUri(imageUri);
            // 后续使用压缩后的Bitmap进行业务操作
        }
    }
}

// 从Uri读取并生成压缩后的Bitmap
private Bitmap getCompressedBitmapFromUri(Uri uri) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    // 先仅读取图片尺寸,不加载到内存
    options.inJustDecodeBounds = true;
    try (InputStream inputStream = getContentResolver().openInputStream(uri)) {
        BitmapFactory.decodeStream(inputStream, null, options);
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }

    // 计算压缩比例,目标尺寸可根据业务需求调整
    int targetWidth = 1080;
    int targetHeight = 1080;
    int width = options.outWidth;
    int height = options.outHeight;
    int inSampleSize = 1;
    if (height > targetHeight || width > targetWidth) {
        int halfWidth = width / 2;
        int halfHeight = height / 2;
        while ((halfHeight / inSampleSize) >= targetHeight && (halfWidth / inSampleSize) >= targetWidth) {
            inSampleSize *= 2;
        }
    }

    // 加载压缩后的图片
    options.inJustDecodeBounds = false;
    options.inSampleSize = inSampleSize;
    options.inPreferredConfig = Bitmap.Config.RGB_565; // 降低内存占用

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

方案2:替换为ACTION_GET_CONTENT(可选)

ACTION_GET_CONTENT的返回逻辑更偏向于传递Uri而非直接数据,部分场景下可避免Parcel过大问题,启动代码调整如下:

public void pickImageFromGallery() {
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.setType("image/*");
    startActivityForResult(intent, SELECT_PICTURE);
}

后续的Uri读取和压缩逻辑与方案1完全一致。

注意事项

  • Android 10及以上版本需适配Scoped Storage权限,确保正常访问媒体文件;
  • 若需上传或保存图片,建议将压缩后的Bitmap保存为文件,避免内存占用过高;
  • 若使用AndroidX库,推荐用ActivityResultContracts.GetContent替代startActivityForResult,适配性更好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 09:25:26