使用CameraX开发安卓相机APP时EXIF数据更新失败无法拍照
问题分析
从错误栈最底层的java.io.IOException: Not a directory可定位核心问题:
- 提前创建空文件干扰EXIF写入:你在调用
imageCapture.takePicture()前手动执行了photoFile.createNewFile(),CameraX的图片捕获流程会自行处理文件创建,提前生成的空文件会导致EXIF工具类在生成临时文件时出现路径识别错误,进而引发EXIF更新失败。 - 权限请求不完整:权限检查时同时验证了
CAMERA和WRITE_EXTERNAL_STORAGE,但实际请求权限时只发起了CAMERA权限申请,若WRITE_EXTERNAL_STORAGE权限缺失,会导致文件写入操作失败。
解决方案
1. 修正拍照按钮的onClick函数
移除手动创建文件的代码,让CameraX自行处理文件创建:
private fun onClick(imageCapture: ImageCapture) { // 创建保存目录 val photoDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES) if (photoDir == null || !photoDir.isDirectory) { Log.d("MainActivity", "Invalid photo directory: $photoDir") return } Log.d("MainActivity", "photoDir: $photoDir") // 生成唯一文件名 val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) val photoFile = File(photoDir, "${timeStamp}.jpg") Log.d("MainActivity", "photoFilePath: ${photoFile.absolutePath}") // 配置输出选项 val outputFileOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build() // 执行拍照 imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback { override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { runOnUiThread { Toast.makeText(this@MainActivity,"Capturing succeeded",Toast.LENGTH_SHORT).show() } } override fun onError(error: ImageCaptureException) { runOnUiThread { Log.d("MainActivity", "Error capturing image: ${error.message}", error) Toast.makeText(this@MainActivity,"Capturing failed",Toast.LENGTH_SHORT).show() } } }) }
2. 修复权限请求逻辑
确保根据系统版本正确请求所需权限(Android 11+无需WRITE_EXTERNAL_STORAGE即可写入应用私有目录):
private fun requestCameraPermissionIfMissing(onResult: ((Boolean) -> Unit)) { val requiredPermissions = mutableListOf<String>() if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { requiredPermissions.add(android.Manifest.permission.CAMERA) } // Android 10及以下需要WRITE权限 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q && ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requiredPermissions.add(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) } if (requiredPermissions.isEmpty()) { onResult(true) } else { registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> val allGranted = permissions.values.all { it } onResult(allGranted) }.launch(requiredPermissions.toTypedArray()) } }
3. 额外优化建议
- 添加
cameraExecutor的销毁逻辑,防止内存泄漏:
override fun onDestroy() { super.onDestroy() cameraExecutor.shutdown() }
内容的提问来源于stack exchange,提问作者Ghost2RM
相关产品推荐
相关产品推荐

