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

Android应用点击图片选择按钮崩溃问题排查求助

点击图库/相机按钮后应用崩溃问题分析与解决

崩溃日志

java.lang.RuntimeException: Could not copy bitmap to parcel blob.
    at android.graphics.Bitmap.nativeWriteToParcel(Native Method)
    at android.graphics.Bitmap.writeToParcel(Bitmap.java:2157)
    at android.os.Parcel.writeParcelable(Parcel.java:2538)
    at android.os.Parcel.writeValue(Parcel.java:2439)
    at android.os.Parcel.writeValue(Parcel.java:2316)
    at android.os.Parcel.writeArrayMapInternal(Parcel.java:1265)
    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1802)
    at android.os.Bundle.writeToParcel(Bundle.java:1362)
    at android.os.Parcel.writeBundle(Parcel.java:1334)
    at android.os.Parcel.writeValue(Parcel.java:2433)
    at android.os.Parcel.writeValue(Parcel.java:2323)
    at android.os.Parcel.writeSparseArray(Parcel.java:1422)
    at android.os.Parcel.writeValue(Parcel.java:2463)
    at android.os.Parcel.writeValue(Parcel.java:2316)
    at android.os.Parcel.writeArrayMapInternal(Parcel.java:1265)
    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1802)
    at android.os.Bundle.writeToParcel(Bundle.java:1362)
    at android.os.Parcel.writeBundle(Parcel.java:1334)
    at android.os.Parcel.writeValue(Parcel.java:2433)
    at android.os.Parcel.writeValue(Parcel.java:2323)
    at android.os.Parcel.writeArrayMapInternal(Parcel.java:1265)
    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1802)
    at android.os.Bundle.writeToParcel(Bundle.java:1362)
    at android.os.Parcel.writeBundle(Parcel.java:1334)
    at android.os.Parcel.writeValue(Parcel.java:2433)
    at android.os.Parcel.writeValue(Parcel.java:2323)
    at android.os.Parcel.writeArrayMapInternal(Parcel.java:1265)
    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1802)
    at android.os.Bundle.writeToParcel(Bundle.java:1362)
    at android.os.Parcel.writeBundle(Parcel.java:1334)
    at android.os.Parcel.writeValue(Parcel.java:2433)
    at android.os.Parcel.writeValue(Parcel.java:2323)
    at android.os.Parcel.writeArrayMapInternal(Parcel.java:1265)
    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1802)
    at android.os.Bundle.writeToParcel(Bundle.java:1362)
    at android.os.Parcel.writeTypedObject(Parcel.java:2157)
    at android.app.IActivityClientController$Stub$Proxy.activityStopped(IActivityClientController.java:1257)
    at android.app.ActivityClient.activityStopped(ActivityClient.java:99)
    at android.app.servertransaction.PendingTransactionActions$StopInfo.run(PendingTransactionActions.java:143)
    at android.os.Handler.handleCallback(Handler.java:942)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:210)
    at android.os.Looper.loop(Looper.java:299)
    at android.app.ActivityThread.main(ActivityThread.java:8247)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:559)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:954)

应用场景与问题详情

应用核心功能是收集用户输入(字符串/数值+多张图片Uri)并构建Record实例,该实例包含8个不同类型的参数,每个参数带有多个属性及唯一图片Uri数组。用户输入分3个Fragment完成:

  1. Fragment1收集3个参数,构建Record(A,B,C)
  2. Fragment2通过setters补充2个参数,得到Record(A,B,C,D),此阶段无崩溃,Record.toString()输出符合预期
  3. Fragment3点击图库/相机按钮时直接崩溃

额外信息:

  • 应用内存占用最高250MB
  • 模拟器中无崩溃,但多款现代Android真机上均出现崩溃
  • 已尝试使用ViewModel,未解决问题

相关代码片段

if (result.getResultCode() == Activity.RESULT_OK) {
    Intent data = result.getData();
    if (data != null && data.getExtras() != null) {
        Bitmap imageBitmap = (Bitmap) data.getExtras().get("data");
        if (imageBitmap != null) {
            Uri capturedImageUri = getImageUri(requireContext(), imageBitmap);
            handleGalleryOrCameraResult(capturedImageUri, requestCode);
        } else {
            // Handle when the imageBitmap is null
        }
    }
}

private void handleGalleryOrCameraResult(Uri selectedImageUri,int requestCode) {
    // Use the appropriate list based on the current scenario
    List<Uri> imageList;
    TextView imageCounter;
    RecyclerView recyclerView;

    switch (requestCode) {
        case 7: // Container
            imageList = DamageGoodImageUris;
            imageCounter = DamageGoodImageCounter;
            recyclerView = DamageGoodRecyclerView;
            break;
        case 8: // Lock
            imageList = HeatImageUris;
            imageCounter = HeatImageCounter;
            recyclerView = HeatRecyclerView;
            break;

        default:
            return;
    }

    // Add the selected image URI to the respective model's image list
    if (selectedImageUri != null) {
        imageList.add(selectedImageUri);
    }

    // Update the RecyclerView with the new image list
    setupRecyclerView(recyclerView, imageList, imageCounter);
}

// Helper method to get Uri from Bitmap
private Uri getImageUri(Context context, Bitmap bitmap) {
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    String path = MediaStore.Images.Media.insertImage(context.getContentResolver(), bitmap, "Title", null);
    return Uri.parse(path);
}

崩溃原因分析

  1. 核心原因:Bitmap体积过大,导致Activity进入后台(启动相机/图库时),系统尝试将Activity状态写入Parcel保存时,Bitmap超出Parcel的大小限制,触发序列化失败。从调用栈可见,崩溃发生在activityStopped阶段,系统正在序列化Activity状态。
  2. 内存占用说明:250MB在现代Android设备上属于偏高但未达异常阈值,但如果Record或Fragment/Activity中持有Bitmap强引用,会加剧内存压力,触发序列化问题。
  3. 代码隐患:当前代码将相机返回的Bitmap转存为Uri的操作冗余,且如果Record或相关对象中持有Bitmap引用,会直接导致序列化失败。

解决方案

1. 移除Record及状态中的Bitmap引用

确保Record实例(或任何需要序列化的对象)只保存图片Uri,绝对不要持有Bitmap对象。所有图片操作均通过Uri加载,避免直接持有大内存对象。

2. 优化相机/图库图片获取逻辑

放弃通过Bitmap中转的方式,直接获取原始图片Uri:

  • 相机:提前创建临时Uri,启动相机时指定输出Uri,直接使用该Uri即可,无需处理Bitmap
  • 图库:直接获取result.getData()返回的Uri,无需转存

示例优化代码:

// 创建相机临时Uri
private Uri createCameraTempUri() {
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.TITLE, "Camera Capture");
    values.put(MediaStore.Images.Media.DESCRIPTION, "From App Camera");
    return requireContext().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
}

// 启动相机
Uri cameraUri = createCameraTempUri();
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri);
startActivityForResult(cameraIntent, CAMERA_REQUEST_CODE);

// 处理结果
if (result.getResultCode() == Activity.RESULT_OK) {
    if (requestCode == CAMERA_REQUEST_CODE) {
        handleGalleryOrCameraResult(cameraUri, requestCode);
    } else if (requestCode == GALLERY_REQUEST_CODE) {
        Uri galleryUri = result.getData();
        if (galleryUri != null) {
            handleGalleryOrCameraResult(galleryUri, requestCode);
        }
    }
}

3. 内存优化与引用清理

  • 使用Glide/Picasso等图片加载库加载RecyclerView图片,自动处理Bitmap缓存与回收
  • 在Fragment销毁时,清空图片列表引用,确保无用Bitmap能被GC回收
  • 检查ViewModel中是否持有Bitmap引用,替换为Uri

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 15:23:19