【问题标题】:Android 5.0+ New SD Card Access API DocumentFile.renameTo() UnsupportedOperationExceptionAndroid 5.0+ 新 SD 卡访问 API DocumentFile.renameTo() UnsupportedOperationException
【发布时间】:2016-05-11 16:18:54
【问题描述】:

我一直在努力解决如何在 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

【问题讨论】:

    标签: android android-sdcard file-rename android-external-storage


    【解决方案1】:

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

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

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

    【讨论】:

    • 非常感谢您的帮助。所以基本上,我必须遍历父目录来查找我要删除的文件。呃,当我有超过 200000 张图像时,这不会需要一段时间吗?我对 DocumentsProvider.Contract 一无所知。你能再解释一下吗?太糟糕了,我不能使用 documentFile.renameTo() :-(
    • @Dante:我的错。我实际上正在查看 DocumentProvider 类,这是错误的(这是文档提供程序的实现)。 DocumentContract 有一个 renameDocument() 方法,你可以试试——看我更正的答案。
    • 太棒了,你简直是天才!我花了几天时间试图弄清楚并在网上搜索。我不能感谢你,我的朋友。非常感谢您的知识和帮助!
    • 如何在 Android KitKat 及以上版本中从 SD 卡中删除文件?
    • 事实上,由于缺少谷歌的文档,只有看一下Android源代码才能澄清事情。 DocumentFile是一个抽象类,该类的对象是SingleDocumentFileTreeDocumentFile。第一个的 createFile()、createDirectory()、renameTo() 和 listFiles() 操作抛出异常。另外还有一个 RawDocumentFile 封装了一个标准的 File 对象。
    【解决方案2】:

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

    尤其是作为 Uri 提供的单个文件,即使程序已被授予相应的写入权限,也无法重命名。这是一个设计缺陷。

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

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

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

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

    注意事项:

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

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

    这很奇怪,它的行为可能是因为你永远不会得到一个带有父级的 DocumentFile,除非你手动遍历树。

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

    【讨论】:

      猜你喜欢
      • 2014-12-31
      • 2015-06-21
      • 1970-01-01
      • 2015-07-27
      • 1970-01-01
      • 2011-11-13
      • 2011-10-17
      • 1970-01-01
      • 2021-02-18
      相关资源
      最近更新 更多