Java 在android 11中如何将图像保存在外部SD卡的DCIM文件夹中?
我正在使用以下代码将图像保存在内部存储器的DCIM文件夹中:Java 在android 11中如何将图像保存在外部SD卡的DCIM文件夹中?,java,android,android-studio,Java,Android,Android Studio,我正在使用以下代码将图像保存在内部存储器的DCIM文件夹中: public Uri saveBitmap(@NonNull final Context context, @NonNull final Bitmap bitmap, @NonNull final Bitmap.CompressFormat format, @NonNull final String mimeType,
public Uri saveBitmap(@NonNull final Context context, @NonNull final Bitmap bitmap,
@NonNull final Bitmap.CompressFormat format,
@NonNull final String mimeType,
@NonNull final String displayName) throws IOException {
final ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName);
values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
final ContentResolver resolver = context.getContentResolver();
Uri uri = null;
try {
final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
uri = resolver.insert(contentUri, values);
if (uri == null)
throw new IOException("Failed to create new MediaStore record.");
try (final OutputStream stream = resolver.openOutputStream(uri)) {
if (stream == null)
throw new IOException("Failed to open output stream.");
if (!bitmap.compress(format, 95, stream))
throw new IOException("Failed to save bitmap.");
}
return uri;
}
catch (IOException e) {
if (uri != null) {
// Don't leave an orphan entry in the MediaStore
resolver.delete(uri, null, null);
}
throw e;
}
}
现在我想把图像保存在外部SD卡的DCIM文件夹中,但我不知道怎么做
我知道我必须对这一行进行更改:
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
但是
环境。目录\u DCIM
始终返回内部存储的DCIM文件夹。您需要使用API 29中引入的新API方法获取现有卷
下一个示例获取卷列表,并尝试所有卷,首先对任何连接的SD卡进行优先级排序,最后在未找到SD卡或无法保存时使用内部存储
您不需要对相对路径内容值进行任何更改,因为它是相对于选定卷的
还要注意的是,我更改了saveBitmap,返回了null,而不是在失败时抛出异常。根据您的要求进行更改
@NonNull
private List<Uri> getContentUris(@NonNull final Context context) {
final List<String> allVolumes = new ArrayList<>();
// Add the internal storage volumes as last resort.
// These will be kept at the bottom of the list if
// any SD-card volumes are found
allVolumes.add(MediaStore.VOLUME_EXTERNAL_PRIMARY);
allVolumes.add(MediaStore.VOLUME_EXTERNAL);
// Obtain the list of volume name candidates
final Set<String> externalVolumeNames = MediaStore.getExternalVolumeNames(context);
for (final String entry : externalVolumeNames) {
// If the volume is "not" already cached in the list,
// then is an SD-card, so prioritize it by adding it
// at the top of the list
if (!allVolumes.contains(entry))
allVolumes.add(0, entry);
}
// Finally resolve the target Image content Uris
final List<Uri> output = new ArrayList<>();
for (final String entry : allVolumes) {
output.add(MediaStore.Images.Media.getContentUri(entry));
}
return output;
}
@Nullable
public Uri saveBitmap(@NonNull final Context context, @NonNull final Bitmap bitmap,
@NonNull final Bitmap.CompressFormat format,
@NonNull final String mimeType,
@NonNull final String displayName) {
final ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName);
values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
final ContentResolver resolver = context.getContentResolver();
final List<Uri> contentUriList = getContentUris(context);
for (final Uri contentUri : contentUriList) {
Uri uri = null;
try {
uri = resolver.insert(contentUri, values);
if (uri == null)
throw new IOException("Failed to create new MediaStore record.");
try (final OutputStream stream = resolver.openOutputStream(uri)) {
if (stream == null)
throw new IOException("Failed to open output stream.");
if (!bitmap.compress(format, 95, stream))
throw new IOException("Failed to save bitmap.");
}
return uri;
}
catch (IOException e) {
Log.w(TAG, "Failed to save in volume: " + contentUri);
if (uri != null) {
// Don't leave an orphan entry in the MediaStore
resolver.delete(uri, null, null);
}
// Do not throw, and try the next volume
}
}
return null;
}
@NonNull
私有列表getContentURI(@NonNull final Context){
最终列表allVolumes=new ArrayList();
//添加内部存储卷作为最后手段。
//如果需要,这些将保留在列表的底部
//找到任何SD卡卷
添加(MediaStore.VOLUME\u EXTERNAL\u PRIMARY);
添加(MediaStore.VOLUME\u外部);
//获取卷名候选列表
最终设置externalVolumeNames=MediaStore.getExternalVolumeNames(上下文);
for(最终字符串条目:externalVolumeNames){
//如果卷“未”已缓存在列表中,
//然后是SD卡,所以通过添加它来确定它的优先级
//排名第一
如果(!allVolumes.contains(条目))
添加(0,条目);
}
//最后解析目标图像内容URI
最终列表输出=新的ArrayList();
for(最终字符串条目:allVolumes){
add(MediaStore.Images.Media.getContentUri(条目));
}
返回输出;
}
@可空
公共Uri保存位图(@NonNull最终上下文,@NonNull最终位图,
@非空最终位图.CompressFormat格式,
@非空的最终字符串mimeType,
@非空的最终字符串(显示名称){
最终ContentValues=新ContentValues();
value.put(MediaStore.MediaColumns.DISPLAY\u NAME,displayName);
value.put(MediaStore.MediaColumns.MIME_类型,mimeType);
value.put(MediaStore.MediaColumns.RELATIVE_PATH,Environment.DIRECTORY_DCIM);
final ContentResolver resolver=context.getContentResolver();
最终列表contentUriList=getContentUris(上下文);
for(最终Uri contentUri:contentUriList){
Uri=null;
试一试{
uri=resolver.insert(contentUri,值);
if(uri==null)
抛出新IOException(“未能创建新的MediaStore记录”);
try(final OutputStream=resolver.openOutputStream(uri)){
if(流==null)
抛出新IOException(“打开输出流失败”);
if(!bitmap.compress(格式,95,流))
抛出新IOException(“保存位图失败”);
}
返回uri;
}
捕获(IOE异常){
Log.w(标记“未能在卷中保存:“+contentUri”);
if(uri!=null){
//不要在MediaStore中留下孤立条目
delete(uri,null,null);
}
//不要扔,试试下一卷
}
}
返回null;
}
最终Uri contentUri=MediaStore.Images.Media.EXTERNAL\u CONTENT\u Uri代码>您只需更改该集合MediaStore.Images.Media.getContentUri(名称)
带有名称,例如从MediaStore.getExternalVolumeNames(上下文)获取的1CD3-23ED(或1CD3-23ED)等值
知道我必须在这一行进行更改:
否。因为这都是相对的。Environment.DIRECTORY\u DCIM始终返回内部存储的DCIM文件夹。
否。它正好等于“DCIM”。