调用相机拍照保存至外部存储时应用崩溃问题排查
解决调用相机Intent拍照存外部存储时权限获取后崩溃的问题
看起来你遇到的问题是在获取相机和存储权限后,调用相机Intent时应用崩溃了。结合你给出的代码片段,我来梳理几个最可能的原因和对应的解决方案:
1. 相机Intent未正确配置输出文件路径
很多时候崩溃的核心原因是没有给相机Intent指定有效的图片存储路径,导致相机App无法完成图片写入操作,进而抛出异常。你需要确保在invokeCamera()方法中创建合法的存储文件,并将其Uri传递给相机Intent。
示例代码如下:
// 定义请求码,用于后续回调处理 private static final int REQUEST_IMAGE_CAPTURE = 1; private String mCurrentPhotoPath; private void invokeCamera() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 先检查设备上是否有相机App可以处理这个Intent,避免找不到相机导致崩溃 if (takePictureIntent.resolveActivity(getPackageManager()) != null) { File photoFile = null; try { photoFile = createImageFile(); } catch (IOException ex) { // 处理文件创建失败的异常,比如提示用户存储异常 ex.printStackTrace(); Toast.makeText(this, "创建图片文件失败", Toast.LENGTH_SHORT).show(); } // 只有文件创建成功时,才启动相机 if (photoFile != null) { // Android 7.0及以上必须用FileProvider获取Uri,不能直接用file:// Uri photoURI = FileProvider.getUriForFile(this, "com.your.package.name.fileprovider", // 这里替换成你的包名+fileprovider photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); } } else { Toast.makeText(this, "未找到可用的相机应用", Toast.LENGTH_SHORT).show(); } } // 生成唯一的图片存储文件 private File createImageFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; // 使用App专属的外部存储目录,不需要额外的存储权限(Android 10+) File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); // 确保存储目录存在 if (!storageDir.exists()) { storageDir.mkdirs(); } return File.createTempFile(imageFileName, ".jpg", storageDir); }
2. 未配置FileProvider(Android 7.0+ 必做)
从Android 7.0开始,系统禁止直接传递file://格式的Uri给其他App,否则会抛出FileUriExposedException导致崩溃。你需要在项目中配置FileProvider:
第一步:在AndroidManifest.xml中添加Provider配置
<application> ... <provider android:name="androidx.core.content.FileProvider" android:authorities="com.your.package.name.fileprovider" <!-- 替换成你的包名+fileprovider --> android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> ... </application>
第二步:创建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"> <!-- 对应getExternalFilesDir(Environment.DIRECTORY_PICTURES)的路径 --> <external-files-path name="my_images" path="Pictures" /> </paths>
3. 权限请求的回调处理不完整
你的代码中权限请求部分没有写完,需要确保在权限请求结果回调中,确认所有权限都被授予后再调用invokeCamera():
private static final int REQUEST_CAMERA_STORAGE_PERMISSIONS = 2; public void dispatchTakePictureIntent(View view) { if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { invokeCamera(); } else { String[] permissionRequest = { Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE }; requestPermissions(permissionRequest, REQUEST_CAMERA_STORAGE_PERMISSIONS); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CAMERA_STORAGE_PERMISSIONS) { boolean allPermissionsGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allPermissionsGranted = false; break; } } if (allPermissionsGranted) { invokeCamera(); } else { Toast.makeText(this, "需要相机和存储权限才能完成拍照", Toast.LENGTH_SHORT).show(); } } }
4. 适配Android 10+的存储权限
Android 10及以上引入了分区存储,如果你使用getExternalFilesDir()这类App专属目录,不需要申请WRITE_EXTERNAL_STORAGE权限,这可以简化权限逻辑,避免不必要的权限申请问题。
内容的提问来源于stack exchange,提问作者lmthrn
相关产品推荐
相关产品推荐

