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

Android新手求助:调用系统相机拍照无法保存至DCIM目录

解决Android调用相机拍照后文件为空的问题

嘿,我来帮你搞定这个问题~你当前遇到的核心问题是调用系统相机拍照后,目标文件是空的,这主要是Uri处理不符合Android版本要求,再加上目录创建和文件名的小问题导致的,咱们一步步来修正:

一、先修正目录创建逻辑(改为DCIM目录)

你原本想把图片存到DCIM目录,但代码里用了Environment.DIRECTORY_PICTURES(这是系统默认的"图片"目录),而且目录创建的代码也有问题,改成下面这样:

private void CreateDirectoryForPictures() {
    // 改用DCIM目录,符合你的需求
    File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
    App.directory = new File(path, "Mahapach_Images");
    // 直接用mkdirs()创建所有不存在的父目录,不需要getParentFile()
    if (!App.directory.exists()) {
        boolean isCreated = App.directory.mkdirs();
        // 加个日志确认目录是否创建成功,方便排查
        Log.d("Camera", "目录创建结果:" + isCreated);
    }
}

二、给图片文件名加上扩展名

你当前的imageFileName没有.jpg后缀,系统相机可能无法识别正确的文件格式,导致无法写入内容,修改文件名生成逻辑:

String imageFileName = "JPEG_" + timeStamp + ".jpg"; // 必须加上.jpg后缀

三、修复跨应用Uri传递问题(Android 7.0+关键)

从Android 7.0开始,系统禁止直接传递file://格式的Uri给其他应用(比如系统相机),否则会抛出FileUriExposedException,必须用FileProvider生成content://格式的安全Uri:

1. 在AndroidManifest.xml中注册FileProvider

<application>标签内添加以下配置:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

(如果用的是旧版support库,把androidx.core.content.FileProvider换成android.support.v4.content.FileProvider

2. 创建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">
    <!-- 共享DCIM目录下的自定义子文件夹 -->
    <external-path
        name="dcim_mahapach"
        path="DCIM/Mahapach_Images/" />
</paths>

3. 修改takeAPicture方法中的Uri生成逻辑

替换原来的Uri.fromFile(App.file),改用FileProvider生成Uri,并添加权限:

private void takeAPicture(){
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    String imageFileName = "JPEG_" + timeStamp + ".jpg"; // 已加后缀
    CreateDirectoryForPictures();
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    App.file = new File(App.directory, imageFileName);
    
    // 生成安全的content:// Uri
    Uri photoUri = FileProvider.getUriForFile(
            this,
            getPackageName() + ".fileprovider", // 和Manifest里的authorities保持一致
            App.file
    );
    intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
    // 给相机应用授予读写Uri的权限,否则无法写入文件
    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    
    // 先判断相机应用是否存在,避免崩溃
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivityForResult(intent, 1);
    }
}

四、补充权限处理(针对Android 6.0+)

如果你的应用目标SDK是23及以上,需要动态申请WRITE_EXTERNAL_STORAGE权限(Android 10及以上启用分区存储后,这个权限可以不用,但为了兼容旧版本还是建议加上):

private static final int REQUEST_PERMISSION = 100;

// 调用拍照前先检查权限
private void checkPermissionAndTakePhoto() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                REQUEST_PERMISSION);
    } else {
        // 权限已授予,执行拍照逻辑
        takeAPicture();
    }
}

// 处理权限申请结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_PERMISSION) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            takeAPicture();
        } else {
            // 用户拒绝权限,提示无法保存图片
            Toast.makeText(this, "需要存储权限才能保存图片", Toast.LENGTH_SHORT).show();
        }
    }
}

最后验证修改后的onActivityResult

媒体扫描的逻辑可以保留,但现在相机拍照后应该能正确写入图片到你指定的DCIM子目录了。


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

火山引擎 最新活动