Получить DocumentFile, который является дочерним для дерева документов, без использования findFiles()

У меня есть URI дерева, который я получил от ACTION_OPEN_DOCUMENT_TREEКак я могу получить DocumentFile, который является дочерним элементом этого дерева, не используяfindFiles()? Учитывая, что я знаю, как получить его 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.

Если я делаю то же, что и выше, но собираю DocumentFile из этого URI с fromTreeUri():

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, представляющий дочерний элемент.

2 ответа

Решение

То, что вы хотите, невозможно с текущими API. Единственный способ получить сделать TreeDocumentFile (частный подкласс DocumentFile что поддерживает createFile, createDirectory, listFiles, а также renameTo) через DocumentFile.fromTreeUri (который дает вам URI корневого дерева, как вы нашли) или через существующий TreeDocumentFile"s listFiles() метод, который есть что findFile использует внутренне.

Вы должны подать запрос на добавление функции на http://issuetracker.google.com/, чтобы добавить новый статический метод, который делает то, что вам нужно.

Возможное решение:

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.

Другие вопросы по тегам