重命名应用程序在 android 10 中创建的 Mediastore 文件。正在处理 Android API 30 但在 API 29 中显示错误

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: 内容移动://media/external/file/116 不允许不属于明确定义的集合

更新-注:

---开始---

为了使用 sdk-29,我们必须使用 Uri 作为 extUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL) 像:

private static Uri extUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL);

代替下面的代码。并将 MediaStore.Files.FileColumns 更新为 MediaStore.Downloads

---结束---

Uri extUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
String relativeLocation = Environment.DIRECTORY_DOWNLOADS + File.separator + "AppFolder";

函数重命名文件(...)

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 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;
}

java.lang.IllegalArgumentException: Movement of content://media/external/file/116 which isn't part of well-defined collection not allowed

所以它是为了 Android 如果你使用 collection;

Q 不允许
Uri extUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);

但是对于 'well-defined collection' 这样的

是允许的
Uri extUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
// Use  "Pictures/MyFolder" for RELATIVE_PATH

我留给你去寻找其他 well-defined collections.

为什么这只适用于 Android Q 我不知道。

您可以在 java 文件中看到消息:https://android.googlesource.com/platform/packages/providers/MediaProvider/+/refs/heads/master/src/com/android/providers/media/MediaProvider.java

引用:

     // 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");
        }

如果重命名失败,请使用 SAF(如前所述)。 How to rename a file in Android knowing only its media content Uri

我不得不自己面对重命名问题 (Android 29),上面的解决方案还不够。

这是因为我有一张物理 SD 卡,上面有 我想重命名的文件。

然后,指令:

extUri = MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);

没用;相反,我不得不:

  1. 列出“外部卷”(根据 Android 条款)

    Set<String> lVls = MediaStore.getExternalVolumeNames(this);
    

    ..这给了我 2 卷:

    "external_primary"    (the built-in external storage)
    "bc21-eafa"           (the SD card external storage)
    
  2. 用第二个值初始化 'extUri',像这样:

    extUri = MediaStore.Audio.Media.getContentUri("bc21-eafa");
    
  3. 应用本文中描述的其余过程。 感谢大家!