Android如何调用系统相机APP拍照且仅在拍照成功时创建存储文件
解决方案
核心实现思路
- 替换废弃的
startActivityForResult,使用Jetpack官方推荐的Activity Result API处理拍照回调 - 针对提前创建空文件的问题,采用「临时文件预创建 + 取消拍照自动删除」的兼容方案:跳转相机前预创建临时文件,在回调中判断如果用户取消拍摄则直接删除该文件,仅拍照成功时保留文件,既避免了多余空文件的产生,也兼容了绝大多数系统/第三方相机APP的全尺寸照片输出逻辑
完整修改代码
首先确保你的项目已经引入了最新的Activity KTX依赖(高版本appcompat默认已包含,无需额外引入)。
1. 声明成员变量与拍照回调
// 存储照片文件路径 private String currentPhotoPath; // 注册拍照结果回调 private ActivityResultLauncher<Uri> takePictureLauncher = registerForActivityResult( new ActivityResultContracts.TakePicture(), isSuccess -> { if (isSuccess) { // 拍照成功,可直接使用currentPhotoPath处理后续逻辑(如展示、上传照片等) } else { // 用户取消拍摄,删除预创建的空临时文件 if (currentPhotoPath != null) { File tempFile = new File(currentPhotoPath); if (tempFile.exists()) { tempFile.delete(); } currentPhotoPath = null; } } } );
2. 保留创建图片文件的工具方法
private File createImageFile() throws IOException { // 生成带时间戳的唯一文件名 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File image = File.createTempFile( imageFileName, /* 文件名前缀 */ ".jpg", /* 文件名后缀 */ storageDir /* 应用私有存储目录,无需申请存储权限 */ ); currentPhotoPath = image.getAbsolutePath(); return image; }
3. 修改触发拍照的逻辑
private void dispatchTakePictureIntent() { // 检查设备是否存在可处理拍照请求的APP Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) == null) { // 无可用相机,可自行添加Toast提示逻辑 return; } File photoFile = null; try { photoFile = createImageFile(); } catch (IOException ex) { // 创建文件失败,可自行添加错误提示逻辑 ex.printStackTrace(); return; } if (photoFile != null) { Uri photoURI = FileProvider.getUriForFile(this, "com.example.android.fileprovider", // 替换为你项目中FileProvider的authorities值 photoFile); // 启动拍照流程 takePictureLauncher.launch(photoURI); } }
注意事项
- 请确保你在
AndroidManifest.xml中正确配置了FileProvider,配置的authorities参数需要和代码中传入的值完全一致 - 如果你的业务仅需要使用缩略图,不需要全尺寸照片,可以使用
ActivityResultContracts.TakePicturePreview协议,直接获取返回的Bitmap后再创建文件写入,完全不需要预创建临时文件,但该方案存在传输过大Bitmap触发TransactionTooLargeException的风险,不适合需要高清照片的场景
内容的提问来源于stack exchange,提问作者Vishnu AV
相关产品推荐
相关产品推荐

