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

Android相机拍照显示至ImageView崩溃求助(图库功能正常)

解决相机拍照崩溃的问题

看起来你的图库选择功能正常,但相机拍照时崩溃,大概率是Android版本适配和权限这两个核心问题导致的,我帮你一步步排查修复:

一、先处理最常见的FileUriExposedException(Android 7.0+)

在Android N及以上系统,直接用Uri.fromFile(file)传递文件Uri会触发FileUriExposedException——系统禁止跨应用暴露file://类型的Uri,必须用FileProvider生成content://类型的Uri来替代。

修复步骤:

  1. 在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>

(如果你用的是support库,把androidx.core.content.FileProvider换成android.support.v4.content.FileProvider)

  1. 创建file_paths.xml配置文件
    在res/xml目录下新建file_paths.xml(没有xml目录就手动创建),内容如下:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="." />
</paths>

这个配置允许FileProvider访问外部存储的根目录。

  1. 修改相机Intent的Uri生成逻辑
    把原来的uri= Uri.fromFile(file);替换成版本适配的代码,同时添加临时权限:
File file=new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    // Android 7.0及以上用FileProvider生成Uri
    uri = FileProvider.getUriForFile(NewAdActivity.this, 
            getPackageName() + ".fileprovider", file);
    // 给相机添加临时读写权限
    camera_intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    camera_intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
} else {
    // 低版本直接用Uri.fromFile
    uri = Uri.fromFile(file);
}

二、检查权限是否齐全

Android 6.0(API 23)及以上,相机权限和存储权限需要动态申请,不能只在Manifest里声明。

1. 在AndroidManifest.xml中声明权限

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Android 10+ 可以用更精细的媒体权限替代 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:maxSdkVersion="33" />
<uses-feature android:name="android.hardware.camera" android:required="false" />

2. 动态申请权限再启动相机

把启动相机的逻辑封装成方法,先检查权限再调用:

// 点击拍照选项时先检查权限
else if (i == 1){//相机
    String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
            || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        // 申请权限
        ActivityCompat.requestPermissions(this, permissions, 100);
    } else {
        // 权限已授予,启动相机
        launchCamera();
    }
}

// 封装的启动相机方法
private void launchCamera() {
    Intent camera_intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    File file=new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        uri = FileProvider.getUriForFile(NewAdActivity.this, 
                getPackageName() + ".fileprovider", file);
        camera_intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        camera_intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    } else {
        uri = Uri.fromFile(file);
    }
    camera_intent.putExtra(MediaStore.EXTRA_OUTPUT,uri);
    // 移除冲突的return-data参数
    // camera_intent.putExtra("return-data",true);
    startActivityForResult(camera_intent,1);
}

3. 处理权限申请结果

重写onRequestPermissionsResult方法:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 100) {
        boolean allGranted = true;
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                allGranted = false;
                break;
            }
        }
        if (allGranted) {
            launchCamera();
        } else {
            Toast.makeText(this, "需要相机和存储权限才能拍照", Toast.LENGTH_SHORT).show();
        }
    }
}

三、移除冲突的return-data参数

当你设置了MediaStore.EXTRA_OUTPUT指定图片保存路径后,return-data设为true是无效的,还可能导致相机返回数据异常,直接删掉这行代码即可。拍照完成后,直接通过你保存的uri加载图片到ImageView:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {
        if (requestCode == 1) {
            // 拍照成功,用uri加载图片
            images.get(current_image).setImageURI(uri);
            fill_images[current_image] = true;
        } else if (requestCode == 2) {
            // 图库选择逻辑保持不变
            Uri selectedUri = data.getData();
            images.get(current_image).setImageURI(selectedUri);
            fill_images[current_image] = true;
        }
    }
}

额外注意点

  • 创建文件前可以先检查外部存储是否可用:if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)),如果存储未挂载,提示用户。
  • 你原来的文件名生成代码String.valueOf(System.currentTimeMillis()+".jpg")可以简化为System.currentTimeMillis() + ".jpg",long类型和字符串拼接会自动转成字符串。

把这些修改都应用后,相机拍照的崩溃问题应该就能解决了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:58:05