John Glen
John Glen

Reputation: 931

DocumentsContract's buildChildDocumentsUriUsingTree(uri, DocumentsContract.getTreeDocumentId(uri)); returns parent Uri tree

I am trying to use DocumentsContract to traverse a directory recursively using the following method.

    void traverseDirectoryEntries(Uri rootUri) {
        ContentResolver contentResolver = activityMain.getContentResolver();
        Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(
                rootUri, DocumentsContract.getTreeDocumentId(rootUri));
        List<Uri> dirNodes = new LinkedList<>();
        dirNodes.add(childrenUri);
        while (!dirNodes.isEmpty()) {
            childrenUri = dirNodes.remove(0); // get the item from top
            try (Cursor cursor = contentResolver.query(childrenUri, new String[]{
                            DocumentsContract.Document.COLUMN_DOCUMENT_ID,
                            DocumentsContract.Document.COLUMN_DISPLAY_NAME,
                            DocumentsContract.Document.COLUMN_MIME_TYPE},
                    null, null, null)) {
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        final String docId = cursor.getString(0);
                        final String name = cursor.getString(1);
                        final String mime = cursor.getString(2);
                        if (isDirectory(mime)) {
                            final Uri newNode = DocumentsContract.buildChildDocumentsUriUsingTree(
                                    rootUri, docId);
                            traverseDirectoryEntries(newNode);
                        }
                    }
                }
            }
        }
    }

    // Util method to check if the mime type is a directory
    private static boolean isDirectory(String mimeType) {
        return DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType);
    }

Unfortunately, this does not work. It goes through the same root directory over and over despite the directory passed in being a child of the root. The line final Uri newNode = DocumentsContract.buildChildDocumentsUriUsingTree(rootUri, docId); returns a Uri with the child directory attached at the end. That works fine. The problem is the follwing line: Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(rootUri, DocumentsContract.getTreeDocumentId(rootUri)); where rootUri is the newNode. I get the same childrenUri; the one I got from rootUri. Is this a bug? Did I make a mistake? Is the docId wrong? I tried getDocumentId(rootUri), but that throws an error because the id it returns is not a tree. It is almost like getTreeDocumentId(rootUri) is returning what getRootId(rootUri) should be returning. Is there a way to fix this?

The rootUri was obtained via ACTION_OPEN_DOCUMENT_TREE. I am running this on Android Pie. I left some code out where I am building a tree structure from the data.

Upvotes: 3

Views: 646

Answers (1)

blackapps
blackapps

Reputation: 9282

You are abusing this well known void traverseDirectoryEntries(Uri rootUri) function.

You think it is recursive but it is not.

Remove the recursive call and instead add 'newNode' to the list.

// traverseDirectoryEntries(newNode);

dirNodes.add(newNode); 

Then you make use of the list.

Then original code is restored.

Who changed it without telling so?

Of course you can adapt this function to make it recursiv.

Nice exercise ;-).

Upvotes: 2

Related Questions