英文:
Rename file of the Mediastore which is created by app in android 10. Working on Android API 30 but shows error in API 29
问题
以下是您提供的代码的翻译部分:
这里,这个 renameFile(..) 函数在 Android API 30 中正常工作。但是,在 Android API 29 中却无法工作,并显示如下错误:
*java.lang.IllegalArgumentException: 不允许移动不属于明确定义的集合的 content://media/external/file/116*
**更新说明:**
**---开始---**
为了在 sdk-29 中正常工作,我们需要使用 Uri,如:extUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL),代码如下:
```java
private static Uri extUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL);
同时,将下面的代码:
Uri extUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
String relativeLocation = Environment.DIRECTORY_DOWNLOADS + File.separator + "AppFolder";
更新为使用 MediaStore.Downloads,代码如下:
Uri extUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL);
String relativeLocation = Environment.DIRECTORY_DOWNLOADS + File.separator + "AppFolder";
---结束---
函数 renameFile(...)
boolean renameFile(Context context, String newName, String displayName) {
try {
Long id = getIdFromDisplayName(displayName);
ContentResolver contentResolver = context.getContentResolver();
Uri mUri = ContentUris.withAppendedId(extUri, id);
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
contentResolver.update(mUri, contentValues, null, null);
contentValues.clear();
contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, newName);
// contentValues.put(MediaStore.Files.FileColumns.MIME_TYPE, "files/pdf");
// contentValues.put(MediaStore.Files.FileColumns.RELATIVE_PATH, relativeLocation);
// contentValues.put(MediaStore.Files.FileColumns.TITLE, "SomeName");
// contentValues.put(MediaStore.Files.FileColumns.DATE_ADDED, System.currentTimeMillis() / 1000);
// contentValues.put(MediaStore.Files.FileColumns.DATE_TAKEN, System.currentTimeMillis());
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
contentResolver.update(mUri, contentValues, null, null);
return true;
} catch (Exception ex) {
ex.printStackTrace();
}
return false;
}
函数 getIdFromDisplayName(...)
@RequiresApi(api = Build.VERSION_CODES.Q)
Long getIdFromDisplayName(String displayName) {
String[] projection;
projection = new String[]{MediaStore.Files.FileColumns._ID};
// TODO 如果在 MediaStore 中没有匹配的项,这会出错。
Cursor cursor = getContentResolver().query(extUri, projection,
MediaStore.Files.FileColumns.DISPLAY_NAME + " LIKE ?", new String[]{displayName}, null);
assert cursor != null;
cursor.moveToFirst();
if (cursor.getCount() > 0) {
int columnIndex = cursor.getColumnIndex(projection[0]);
long fileId = cursor.getLong(columnIndex);
cursor.close();
return fileId;
}
return null;
}
<details>
<summary>英文:</summary>
Here, this renameFile(..) func is working in Android API 30. But, it is not working in Android API 29 and shows the error like :
*java.lang.IllegalArgumentException: Movement of content://media/external/file/116 which isn't part of well-defined collection not allowed*
**Update-Note:**
**---Begins---**
**In-order to work with sdk-29 we have to use Uri as extUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL) like:**
private static Uri extUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL);
in place of below code. And also update **MediaStore.Files.FileColumns** to **MediaStore.Downloads**
**---Ends---**
Uri extUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
String relativeLocation = Environment.DIRECTORY_DOWNLOADS + File.separator + "AppFolder";
**function renameFile(...)**
boolean renameFile(Context context, String newName, String displayName) {
try {
Long id = getIdFromDisplayName(displayName);
ContentResolver contentResolver = context.getContentResolver();
Uri mUri = ContentUris.withAppendedId(extUri, id);
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
contentResolver.update(mUri, contentValues, null, null);
contentValues.clear();
contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, newName);
// contentValues.put(MediaStore.Files.FileColumns.MIME_TYPE, "files/pdf");
// contentValues.put(MediaStore.Files.FileColumns.RELATIVE_PATH, relativeLocation);
// contentValues.put(MediaStore.Files.FileColumns.TITLE, "SomeName");
// contentValues.put(MediaStore.Files.FileColumns.DATE_ADDED, System.currentTimeMillis() / 1000);
// contentValues.put(MediaStore.Files.FileColumns.DATE_TAKEN, System.currentTimeMillis());
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
contentResolver.update(mUri, contentValues, null, null);
return true;
} catch (Exception ex) {
ex.printStackTrace();
}
return false;
}
**function getIdFromDisplayName(...)**
@RequiresApi(api = Build.VERSION_CODES.Q)
Long getIdFromDisplayName(String displayName) {
String[] projection;
projection = new String[]{MediaStore.Files.FileColumns._ID};
// TODO This will break if we have no matching item in the MediaStore.
Cursor cursor = getContentResolver().query(extUri, projection,
MediaStore.Files.FileColumns.DISPLAY_NAME + " LIKE ?", new String[]{displayName}, null);
assert cursor != null;
cursor.moveToFirst();
if (cursor.getCount() > 0) {
int columnIndex = cursor.getColumnIndex(projection[0]);
long fileId = cursor.getLong(columnIndex);
cursor.close();
return fileId;
}
return null;
}
</details>
# 答案1
**得分**: 6
```java
java.lang.IllegalArgumentException: 不允许移动不属于明确定义的集合的内容:content://media/external/file/116
因此,对于使用集合的情况,Android Q不允许;
Uri extUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
但是对于“明确定义的集合”是允许的,比如:
Uri extUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
// 使用 "Pictures/MyFolder" 作为 RELATIVE_PATH
我将其他明确定义的集合的查找工作交给你。
为什么这仅限于Android Q,我不清楚。
您可以在Java文件中看到此消息:https://android.googlesource.com/platform/packages/providers/MediaProvider/+/refs/heads/master/src/com/android/providers/media/MediaProvider.java
摘录:
// 我们仅支持在明确定义的集合下进行移动
switch (match) {
case AUDIO_MEDIA_ID:
case VIDEO_MEDIA_ID:
case IMAGES_MEDIA_ID:
case DOWNLOADS_ID:
break;
default:
throw new IllegalArgumentException("不允许移动不属于明确定义的集合的内容:" + uri);
}
如果重命名失败,请使用SAF(如前所述)。https://stackoverflow.com/questions/55314476/how-to-rename-a-file-in-android-knowing-only-its-media-content-uri
英文:
>> java.lang.IllegalArgumentException: Movement of content://media/external/file/116 which isn't part of well-defined collection not allowed
So it is for Android Q not allowed if you use the collection;
Uri extUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
But is is allowed for a 'well-defined collection' like:
Uri extUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
// Use "Pictures/MyFolder" for RELATIVE_PATH
I leave it to you to find other well-defined collections.
Why this is only for Android Q i dont know.
You can see the message in the java file: https://android.googlesource.com/platform/packages/providers/MediaProvider/+/refs/heads/master/src/com/android/providers/media/MediaProvider.java
Quote:
// We only support movement under well-defined collections
switch (match) {
case AUDIO_MEDIA_ID:
case VIDEO_MEDIA_ID:
case IMAGES_MEDIA_ID:
case DOWNLOADS_ID:
break;
default:
throw new IllegalArgumentException("Movement of " + uri
+ " which isn't part of well-defined collection not allowed");
}
If the rename fails use SAF (as mentioned before). https://stackoverflow.com/questions/55314476/how-to-rename-a-file-in-android-knowing-only-its-media-content-uri
答案2
得分: 1
我认为这是Android 10 mediaprovider中的一个系统错误。
在Android 10中,代码如下:
// 仅支持在明确定义的集合下进行移动
switch (match) {
case AUDIO_MEDIA_ID:
case VIDEO_MEDIA_ID:
case IMAGES_MEDIA_ID:
case DOWNLOADS_ID:
break;
default:
throw new IllegalArgumentException("不允许移动不属于明确定义的集合的 " + uri);
}
在Android 11中,代码如下:
final boolean allowMovement = extras.getBoolean(MediaStore.QUERY_ARG_ALLOW_MOVEMENT,
!isCallingPackageSelf());
if (containsAny(initialValues.keySet(), sPlacementColumns)
&& !initialValues.containsKey(MediaColumns.DATA)
&& !isThumbnail
&& allowMovement) {
Trace.beginSection("movement");
// 仅支持在明确定义的集合下进行移动
switch (match) {
case AUDIO_MEDIA_ID:
case AUDIO_PLAYLISTS_ID:
case VIDEO_MEDIA_ID:
case IMAGES_MEDIA_ID:
case DOWNLOADS_ID:
case FILES_ID:
break;
default:
throw new IllegalArgumentException("不允许移动不属于明确定义的集合的 " + uri);
}
}
英文:
I think it's a system bug in Android 10 mediaprovider.
In android 10,it is like this
// We only support movement under well-defined collections
switch (match) {
case AUDIO_MEDIA_ID:
case VIDEO_MEDIA_ID:
case IMAGES_MEDIA_ID:
case DOWNLOADS_ID:
break;
default:
throw new IllegalArgumentException("Movement of " + uri
+ " which isn't part of well-defined collection not allowed");
}
in Android 11,it is like this
final boolean allowMovement = extras.getBoolean(MediaStore.QUERY_ARG_ALLOW_MOVEMENT,
!isCallingPackageSelf());
if (containsAny(initialValues.keySet(), sPlacementColumns)
&& !initialValues.containsKey(MediaColumns.DATA)
&& !isThumbnail
&& allowMovement) {
Trace.beginSection("movement");
// We only support movement under well-defined collections
switch (match) {
case AUDIO_MEDIA_ID:
case AUDIO_PLAYLISTS_ID:
case VIDEO_MEDIA_ID:
case IMAGES_MEDIA_ID:
case DOWNLOADS_ID:
case FILES_ID:
break;
default:
throw new IllegalArgumentException("Movement of " + uri
+ " which isn't part of well-defined collection not allowed");
}
答案3
得分: 0
我不得不亲自面对重命名问题(Android 29),上述解决方案不足够。
这是因为我有一张物理 SD 卡,上面有我想要重命名的文件。
然后,以下指令:
extUri = MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
没有起作用;相反,我不得不:
- 列出“外部卷”(根据 Android 的术语)
Set<String> lVls = MediaStore.getExternalVolumeNames(this);
..这给了我两个卷:
"external_primary"(内置外部存储)
"bc21-eafa"(SD 卡外部存储)
- 使用第二个值来初始化 'extUri',像这样:
extUri = MediaStore.Audio.Media.getContentUri("bc21-eafa");
- 像本文中描述的那样,应用剩下的步骤。感谢大家!
英文:
I had to face the rename problem myself (Android 29) and the solution above did not suffice.
This was because I had a physical SD card on which were located the
files I wanted to rename.
Then, instruction:
extUri = MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
did not work; instead,I had to:
-
list the "external volumes"(according to Android terms)
Set<String> lVls = MediaStore.getExternalVolumeNames(this);
..which gave me 2 volumes:
"external_primary" (the built-in external storage) "bc21-eafa" (the SD card external storage)
-
Initialize 'extUri' with that second value, like that:
extUri = MediaStore.Audio.Media.getContentUri("bc21-eafa");
-
Apply the rest of the procedure as described in this article.
Thanks to all !
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论