Android 5.0+ 新的SD卡访问API文档文件DocumentFile.renameTo()不支持操作异常。

3

我一直在努力学习如何在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$21.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
2个回答

8

renameTo() 方法不支持从 fromSingleUri() 创建的 DocumentFile

您可以尝试使用 DocumentsContract.renameDocument(getContentResolver(), uri, theNewDisplayName)getContentResolver()Context 上的一个方法,用于获取 ContentResolver。请注意,这会更改显示名称;“显示名称”的解释取决于文档提供程序。此外,并非所有提供程序都支持重命名文档,因此可能起作用,也可能不起作用。

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


非常感谢您的帮助。基本上,我必须循环遍历父目录以查找我要删除的文件。嗯,当我有超过200000张图片时,这会花费很长时间,不是吗?我对DocumentsProvider.Contract一无所知。您能再详细解释一下吗?不能使用documentFile.renameTo()真糟糕 :-( - Dante
@Dante:我的错误。我实际上是在看DocumentProvider类,这是错误的(那是一个文档提供者的实现)。DocumentContract有一个renameDocument()方法,你可以尝试一下--请看我的更正答案。 - CommonsWare
太棒了,你真是个天才!我花了好几天的时间试图弄清楚它并在网上搜索。我的朋友,我无法感谢你足够了。非常感谢你的知识和帮助! - Dante
1
如何在Android KitKat及以上版本中从SD卡中删除文件? - hasnain_ahmad
补充说明:fromSingleUri()和fromTreeUri()都将父级设置为null。因此,getParentFile()方法并不真正有用。 - Andreas K. aus M.
显示剩余3条评论

0

如前所述,createFile()createDirectory()renameTo()listFiles() 操作在由 fromSingleUri() 创建的对象上抛出异常。

特别是单个文件,即使程序已被授予相应的写入权限,也无法重命名。这是一个设计缺陷。

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

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

  1. 使用常规的ACTION_OPEN_DOCUMENT_TREE方法请求权限。
  2. 使用grantUriPermission()和takePersistableUriPermission()获取权限。
  3. 每当您稍后收到SingleDocumentUri时,都可以使用getPersistedUriPermissions()获取存储的权限URI。
  4. 循环遍历权限并跳过所有不匹配授权和第一个组件不是"tree"而是"document"的权限。
  5. 检查权限的第二个组件是否是SingleDocumentFile的第二个组件的前缀。如果是,则已经被授予必要的权限。
  6. 一旦找到匹配的权限,请从中创建TreeDocumentFile,并使用findFile()向上遍历树,直到找到文档。路径组件分隔符可以是"/"或":",也可能是其他字符。可能需要使用不同的文档提供程序测试该方法。
  7. 最后的findFile()将为您提供一个具有父级等的匹配TreeDocumentFile,可用于重命名。

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

注:

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

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

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接