Android相机图片保存失败求助:无法存至Pictures目录
先给你吃个定心丸:完全没必要切换到Camera2,你现在用的这套基于MediaStore.ACTION_IMAGE_CAPTURE的方案完全能搞定需求,我们只需要把几个配置和代码的小问题修正就行。
问题1:FileProvider路径配置不匹配
你当前的file_paths.xml指向的是应用私有存储的Pictures目录,但你的createImageFile()是在公共Pictures目录下创建文件,两者不对应,这会导致相机无法正确写入文件。
修改res/xml/file_paths.xml:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 公共Pictures目录的配置,对应你要存的ConSp子文件夹 --> <external-public-path name="my_images" path="Pictures/ConSp" /> </paths>
问题2:createImageFile()的两个小疏漏
一是你没有给currentPhotoPath赋值,导致后续无法获取完整文件路径存入数据库;二是没有创建指定的子文件夹ConSp。
修改createImageFile()方法:
String currentPhotoPath; private File createImageFile(){ // 1. 创建Pictures下的ConSp子文件夹 File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "ConSp"); if (!storageDir.exists()) { if (!storageDir.mkdirs()) { Log.d("Confined_Space", "failed to create Directory"); return null; } } // 2. 生成带时间戳的文件名 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String imageFileName = "ConSp_" + timeStamp + ".jpg"; File photoFile = new File(storageDir, imageFileName); // 3. 保存文件绝对路径,后续存数据库用 currentPhotoPath = photoFile.getAbsolutePath(); return photoFile; }
加上Locale.getDefault()可以避免日期格式化的地域适配问题。
问题3:onActivityResult()错误获取图片
当你通过EXTRA_OUTPUT指定了保存路径后,data.getExtras().get("data")返回的只是缩略图,不是你实际保存的全尺寸图片,甚至data可能为null。我们需要直接用之前保存的currentPhotoPath来加载图片:
修改onActivityResult():
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { // 用currentPhotoPath加载全尺寸图片 // 注意:直接用BitmapFactory.decodeFile可能触发OOM,建议用Glide/Coil等图片库 // 这里用BitmapFactory做示例(需处理内存): BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 4; // 缩小4倍,可根据需求调整 Bitmap imageBitmap = BitmapFactory.decodeFile(currentPhotoPath, options); imageView.setImageBitmap(imageBitmap); // 在这里把currentPhotoPath存入你的SQLite数据库 // 示例:dbHelper.insertImageRecord(currentPhotoPath); } }
问题4:权限适配(针对不同Android版本)
你的Manifest里已经加了基础权限,但还需要处理动态权限申请和安卓10+的Scoped Storage限制:
- 安卓6.0(API23)- 安卓9(API28):需要在调用相机前动态申请
WRITE_EXTERNAL_STORAGE权限:
private void dispatchTakePictureIntent() { // 检查存储权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1001); return; } // 原有的相机启动逻辑... }
记得重写onRequestPermissionsResult()处理权限申请结果,用户同意后再重新调用相机方法。
- 安卓10(API29)及以上:如果想继续使用公共Pictures目录,需要在Manifest的
application标签里添加:
android:requestLegacyExternalStorage="true"
这个属性会让应用暂时绕过Scoped Storage限制,对于你的基础拍照需求来说,这是最简单的适配方式。
最后:关于Camera2
真的不需要换!Camera2 API功能更强大但复杂度也高很多,你现在的需求只是基础拍照+保存,修改上面的几个点就能完美解决问题,没必要折腾更复杂的API。
内容的提问来源于stack exchange,提问作者dlowey




