Android 5.0+ 新 SD 卡访问 API DocumentFile.renameTo() UnsupportedOperationException

Android 5.0+ New SD Card Access API DocumentFile.renameTo() UnsupportedOperationException

我一直在苦苦思索如何重命名 Lollipop 上的 DocumentFile。 很抱歉,我曾尝试到处搜索解决方案,但网上似乎缺少有关此新 SD 卡访问的信息 API。

这是我的:

        String EditText = (Alert_EditText.getText().toString()).trim();
        Uri uri = ListViewObject_List.get(LastItemPos).getImageUri();
        final DocumentFile documentFile = DocumentFile.fromSingleUri(MainClass.this, uri);
        documentFile.renameTo(EditText);

出现了 UnsupportedOperationException:

FATAL EXCEPTION: main
Process: com.camera.test, PID: 3362
java.lang.UnsupportedOperationException
at android.support.v4.provider.SingleDocumentFile.renameTo(SingleDocumentFile.java:105)
at com.camera.test.MainClass.onClick(MainClass.java:986)
at android.view.View.performClick(View.java:5242)
at android.widget.TextView.performClick(TextView.java:10530)
at android.view.View$PerformClick.run(View.java:21185)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6872)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)

我也试过这个:

    String EditText = (Alert_EditText.getText().toString()).trim();
    Uri uri = ListViewObject_List.get(LastItemPos).getImageUri();
    File file = new File(uri.getPath());
    final DocumentFile documentFile = DocumentFile.fromFile(file);
    documentFile.renameTo(EditText);    

它似乎什么也没做:没有错误,什么也没发生...

.....

..... 我可以通过以下方式删除 DocumentFile:

Uri uri = ListViewObject_List.get(LastItemPos).getImageUri();
final DocumentFile documentFile = DocumentFile.fromSingleUri(MainClass.this, uri);
documentFile.delete();

有人可以看一下我做错了什么吗?

非常感谢您的好意和帮助。

更新: 这个 uri 是

content://com.android.externalstorage.documents/tree/0000-0000%3APictures%2FTest1/document/0000-0000%3APictures%2FTest1%2FMyPicture.jpg
fromSingleUri() 创建的 DocumentFile 不支持

renameTo()

你可以试试DocumentsContract.renameDocument(getContentResolver(), uri, theNewDisplayName)getContentResolver() 是在 Context 上获得 ContentResolver 的方法。请注意,这会更改显示名称; "display name" 的解释取决于文档提供者。此外,并非所有提供商都支持重命名文档,因此这可能有效也可能无效。

请注意,存储访问提供程序不是 "SD Card Access API"。这是一个文档 API。这些文档来自用户选择的文档提供者,可能涉及也可能不涉及可移动存储。

如前所述,createFile()createDirectory()renameTo() listFiles() 操作在 fromSingleUri().

创建的对象上抛出异常

特别是作为 Uri 提供的单个文件不能重命名,即使该程序已经被授予相应的写权限。这是一个设计缺陷。

此外,提到的函数 DocumentsContract.renameDocument() 在我的所有测试中都失败了,所以我不知道是为了什么而设计的。

但是,我找到了一个相当复杂的解决方案,它基于授予的文档树权限:

  1. 使用通常的 ACTION_OPEN_DOCUMENT_TREE 方法请求权限。
  2. 使用 grantUriPermission()takePersistableUriPermission().
  3. 获取权限
  4. 每当您稍后收到 SingleDocumentUri 时,使用 getPersistedUriPermissions() 获取存储的权限 URI。
  5. 遍历权限并跳过所有权限不匹配且第一个组件不是“树”而是“文档”的权限。
  6. 检查权限的第二个组件是否是您的 SingleDocumentFile 第二个组件的前缀。如果是,则您已获得必要的权限。
  7. 找到匹配的权限后,从中创建一个 TreeDocumentFile 并使用 findFile() 在树上向上走,直到找到您的文档。路径组件分隔符可以是“/”或“:”,也可能是其他分隔符。可能需要使用不同的文档提供程序测试该方法。
  8. 最后的 findFile() 会给你一个匹配的 TreeDocumentFile 与父级等,可用于重命名。

如果您在权限中没有找到匹配的树,您可以要求用户授予缺少的权限,即第 1 步。

备注:

如果您为任意目录 URI 调用 fromTreeUri(),您可能会得到一个 TreeDocumentFile,但不是针对相应的目录,但对于下面的目录,您已经拥有以下权限.因此,在调用 fromTreeUri() 之后,您还可以沿着树向上走,调用 findFile() 直到到达您要访问的目录。

我也尝试了 DocumentsContract.buildTreeDocumentUri() 但结果不可用,即我得到了一个 TreeDocumentUri 但仍然无法重命名文件。

这一切都非常奇怪,它的行为可能是因为您永远不会获得具有父级的 DocumentFile,除非您手动遍历树。

如果有人找到更优雅的解决方案,请告诉!