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

Android 6调用相机拍照并显示图片异常问题

解决Android 6调用相机Intent拍照后Resume时的RuntimeException问题

嘿,针对你遇到的Android 6上调用系统相机拍照后,在ActivityThread.performResumeActivity抛出RuntimeException的问题,我整理了几个最可能的原因和对应的解决办法:

1. 动态权限未正确申请(最常见原因)

Android 6.0(API 23)开始引入了动态权限机制,CAMERA和WRITE_EXTERNAL_STORAGE都属于危险权限,只在AndroidManifest.xml中声明是不够的,必须在代码中主动申请并获得用户授权。如果权限缺失,相机操作会异常,进而在Activity恢复时触发崩溃。

解决步骤:

  • 先在Manifest中声明基础权限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
  • 在调用相机Intent前,检查并申请权限:
private static final int REQUEST_PERMISSIONS = 100;

// 检查权限是否已授权
private boolean checkPermissions() {
    int cameraPerm = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
    int storagePerm = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    return cameraPerm == PackageManager.PERMISSION_GRANTED && storagePerm == PackageManager.PERMISSION_GRANTED;
}

// 发起权限申请
private void requestPermissions() {
    ActivityCompat.requestPermissions(this,
            new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
            REQUEST_PERMISSIONS);
}

// 处理权限申请结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_PERMISSIONS) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 权限通过,启动相机
            launchCameraIntent();
        } else {
            Toast.makeText(this, "需要相机和存储权限才能完成拍照", Toast.LENGTH_SHORT).show();
        }
    }
}

记得只有在权限通过后,再启动相机Intent。

2. 文件存储Uri的权限问题(适配FileProvider)

虽然Android 7.0才强制要求用content:// Uri替代file:// Uri,但部分Android 6的定制ROM也会限制第三方应用访问file:// Uri指向的文件,导致相机无法写入你指定的图片文件,最终在Activity恢复时引发异常。

解决步骤:

  • 在AndroidManifest.xml中添加FileProvider声明:
<application ...>
    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
</application>
  • 在res/xml目录下创建file_paths.xml,指定允许访问的文件路径:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="my_images" path="Pictures/" />
</paths>
  • 生成Content Uri并启动相机Intent:
private File createImageFile() throws IOException {
    // 创建临时图片文件
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    return File.createTempFile(imageFileName, ".jpg", storageDir);
}

private void launchCameraIntent() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        File photoFile = null;
        try {
            photoFile = createImageFile();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        if (photoFile != null) {
            Uri photoURI = FileProvider.getUriForFile(this,
                    getPackageName() + ".fileprovider",
                    photoFile);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
            // 授予相机应用写入权限
            takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
        }
    }
}

3. Bitmap加载/缩放导致的内存溢出(OOM)

如果拍照后的原图尺寸过大,直接加载为Bitmap可能会导致内存溢出,进而在Activity Resume时触发RuntimeException。

解决步骤:

加载图片时用BitmapFactory.Options进行采样缩放,避免加载完整尺寸的图片:

private Bitmap getScaledBitmap(String filePath, int targetWidth, int targetHeight) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    // 先只获取图片尺寸,不加载Bitmap到内存
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, options);
    
    // 计算合适的采样率
    options.inSampleSize = calculateInSampleSize(options, targetWidth, targetHeight);
    
    // 加载缩放后的Bitmap
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(filePath, options);
}

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;

        // 找到最大的采样率,保证缩放后图片不小于目标尺寸
        while ((halfHeight / inSampleSize) >= reqHeight
                && (halfWidth / inSampleSize) >= reqWidth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

在onActivityResult中拿到图片路径后,调用上述方法加载缩放后的Bitmap,再设置到ImageView中。


你可以先从动态权限检查入手,这是Android 6上相机相关崩溃最常见的原因,再逐步排查Uri适配和Bitmap加载的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:41:15