3

我有一个从中获得的树 URI ACTION_OPEN_DOCUMENT_TREE如何在不使用的情况下获得作为该树的子项的 DocumentFilefindFiles()?鉴于我知道如何获取它的 documentId、它的绝对路径或它的 URI。我需要与文档树相关的权限。

这就是我现在所拥有的:

DocumentFile rootTree = DocumentFile.fromTreeUri(context, rootTreeUri);
DocumentFile docFile = rootTree.findFile(fileName);

docFile以 TreeDocumentFile 的形式返回,它是我的根目录的子项。我有写权限并且可以使用createFile()它,因为它位于ACTION_OPEN_DOCUMENT_TREE.

所以它有效,但findFile()真的很慢。

如果我尝试像这样使用 DocumentsContract:

// I know how to build the documentId from the file's absolute path
Uri uri = DocumentsContract.buildTreeDocumentUri(rootTreeUri.getAuthority(), documentId);
DocumentFile docFile = DocumentFile.fromTreeUri(context, uri);
// Result: "content://com.android.externalstorage.documents/tree/1A0E-0E2E:myChildDirectory/document/1A0E-0E2E:myChildDirectory"

它返回一个以 为根的新 TreeDocumentFile docFile,而不是docFile作为我的原始文档树(根)的子级。所以我没有这棵树的写权限。

如果我这样尝试:

Uri docUri = DocumentsContract.buildDocumentUriUsingTree(rootTreeUri, documentId);
// Result: "content://com.android.externalstorage.documents/tree/1A0E-0E2E:/document/1A0E-0E2E:myChildDirectory"

我得到一个实际上看起来像我想要的 URI,但它是一个 URI,而不是 DocumentFile。

如果我执行与上述相同的操作,但使用 fromTreeUri() 从该 uri 构建 DocumentFile:

Uri docUri = DocumentsContract.buildDocumentUriUsingTree(rootTreeUri, documentId);
DocumentFile docFile = DocumentFile.fromTreeUri(context, docUri);
// Result: "content://com.android.externalstorage.documents/tree/1A0E-0E2E:/document/1A0E-0E2E:"

我得到了原始树 DocumentFile,而不是代表孩子的 DocumentFile。

4

2 回答 2

4

当前的 API 无法实现您想要的。制作TreeDocumentFileDocumentFile (支持createFilecreateDirectorylistFiles和的私有子类renameTo)的唯一方法是通过DocumentFile.fromTreeUri(它只为您提供您找到的根树 URI)或通过现有TreeDocumentFilelistFiles()方法,这是findFile内部使用的方法.

您应该在issuetracker.google.com上提交功能请求,以添加一个新的静态方法来满足您的需求。

于 2017-09-12T16:17:30.833 回答
0

有可能的解决方案:

https://www.reddit.com/r/androiddev/comments/orytnx/fixing_treedocumentfilefindfile_lousy_performance/

以下是来自上述链接的引用:

  @Nullable
static public DocumentFile findFile(@NonNull context, @NonNull DocumentFile documentFile, @NonNull String displayName) {


    if(!(documentFile instanceof TreeDocumentFile)) {
        return documentFile.findFile(displayName);
    }

    final ContentResolver resolver = context.getContentResolver();
    final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(documentFile.getUri(),
            DocumentsContract.getDocumentId(documentFile.getUri()));

    Cursor c = null;
    try {
        c = resolver.query(childrenUri, new String[] {
                DocumentsContract.Document.COLUMN_DOCUMENT_ID,
                DocumentsContract.Document.COLUMN_DISPLAY_NAME,
        }, null, null, null);

        if(c != null) {
            while (c.moveToNext()) {
                if (displayName.equals(c.getString(1))) {
                    return new TreeDocumentFile(documentFile,
                            context,
                            DocumentsContract.buildDocumentUriUsingTree(documentFile.getUri(), c.getString(0)));
                }
            }
        }
    } catch (Exception e) {
        Log.w(TAG, "query failed: " + e);
    } finally {                 
        IOUtils.closeQuietly(c);
    }

    return null;
}

请注意,要访问包受保护的类 TreeDocumentFile,您必须将上述函数放在包 androidx.documentfile.provider 的帮助器类中。在此之后,将 DocumentFile#findFile 的所有调用替换为此替换或其 Kotlin 改编版本。

于 2021-10-06T08:37:32.413 回答