You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android相机图片保存失败求助:无法存至Pictures目录

不用换Camera2!一步步解决你的照片保存与路径存储问题

先给你吃个定心丸:完全没必要切换到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限制:

  1. 安卓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()处理权限申请结果,用户同意后再重新调用相机方法。

  1. 安卓10(API29)及以上:如果想继续使用公共Pictures目录,需要在Manifest的application标签里添加:
android:requestLegacyExternalStorage="true"

这个属性会让应用暂时绕过Scoped Storage限制,对于你的基础拍照需求来说,这是最简单的适配方式。

最后:关于Camera2

真的不需要换!Camera2 API功能更强大但复杂度也高很多,你现在的需求只是基础拍照+保存,修改上面的几个点就能完美解决问题,没必要折腾更复杂的API。

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

火山引擎 最新活动