Android开发:使用Uri将图片保存至新建子文件夹报错咨询
错误原因
你的两种实现报错核心是对分区存储下MediaStore的Uri规则理解错误:
- V1版本用
Uri.fromFile()生成的是file://协议的本地文件Uri,Android 10及以上开启分区存储后,应用无法直接通过文件路径访问公共存储目录,MediaStore接口不接受这类文件Uri,因此触发写入失败。 - V2版本直接在媒体库图片根Uri后拼接子文件夹路径的写法完全不符合MediaStore的Uri规则:
MediaStore.Images.Media.EXTERNAL_CONTENT_URI是图片集合的根入口,后面仅允许拼接具体媒体条目的数字ID,不支持直接拼接路径字符串,因此会抛出不支持URL的错误。
正确实现方案
你不需要单独获取子文件夹对应的Uri——MediaStore体系下不存在子文件夹独立的访问Uri,子目录是通过ContentValues的RELATIVE_PATH字段指定的,系统会自动创建不存在的目录,不需要你手动调用mkdir()。
核心配置
删除你代码中手动创建文件夹、拼接uri1/uri2的逻辑,在构造ContentValues时新增相对路径配置,根Uri仍使用图片集合的根Uri即可:
String FotoString="picture1"; ContentValues contentValues=new ContentValues(); contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, FotoString); contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg"); // 指定存储到Pictures目录下的ProxF子文件夹,系统自动创建不存在的目录 contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/ProxF"); // 根Uri保持不变,不要拼接任何子路径 Uri validUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; ImageCapture.OutputFileOptions fileOptions= new ImageCapture.OutputFileOptions.Builder(getContentResolver(),validUri,contentValues).build();
低版本兼容(可选,适配Android 9及以下)
RELATIVE_PATH字段从Android 10(API 29)开始支持,如果需要兼容更低版本,做版本分支处理即可:
final String FotoString="picture1"; ImageCapture.OutputFileOptions fileOptions; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ContentValues contentValues=new ContentValues(); contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, FotoString); contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg"); contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/ProxF"); Uri imageCollectionUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; fileOptions = new ImageCapture.OutputFileOptions.Builder(getContentResolver(),imageCollectionUri,contentValues).build(); } else { // 低版本手动创建目录,通过文件路径构造OutputFileOptions File proxFDir = new File(getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "ProxF"); if (!proxFDir.exists()) { proxFDir.mkdirs(); } File photoFile = new File(proxFDir, FotoString + ".jpg"); fileOptions = new ImageCapture.OutputFileOptions.Builder(photoFile).build(); } // 后续直接用fileOptions调用takePicture即可
注意事项
- 不要尝试给公共目录的子文件夹生成独立Content Uri,MediaStore没有提供这类Uri的获取入口,所有公共目录下的媒体写入,都通过根集合Uri+RELATIVE_PATH字段指定存储位置
- Android 10及以上版本不需要手动调用
mkdir()创建子目录,系统会根据RELATIVE_PATH的配置自动创建缺失的目录 - 确保你申请的存储权限符合对应版本要求:Android 13及以上申请
READ_MEDIA_IMAGES权限,Android 10-12申请READ_EXTERNAL_STORAGE,Android 9及以下同时申请READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE
内容的提问来源于stack exchange,提问作者ProxoJ
相关产品推荐
相关产品推荐

