queryRoots сначала вызывает queryDocument, а не queryChildDocuments - PullRequest
1 голос
/ 07 апреля 2019

Я пишу оболочку для SAF-оболочки для Dropbox, поскольку все (включая Google) слишком ленивы, чтобы реализовать этот «очень богатый» (то есть: ужасный) API. У меня есть мой корень в сборщике, но я подумал, что сначала надо вызвать queryChildren. Однако queryChildren is never called and it goes straight to queryDocument`.

override fun queryRoots(projection: Array<out String>?): Cursor {
    // TODO: Likely need to be more strict about projection (ie: map to supported)
    val result = MatrixCursor(projection ?: DEFAULT_ROOT_PROJECTION)

    val row = result.newRow()
    row.add(DocumentsContract.Root.COLUMN_ROOT_ID, "com.anthonymandra.cloudprovider.dropbox")
    row.add(DocumentsContract.Root.COLUMN_ICON, R.drawable.ic_dropbox_gray)
    row.add(DocumentsContract.Root.COLUMN_TITLE, "Dropbox")
    row.add(DocumentsContract.Root.COLUMN_FLAGS, DocumentsContract.Root.FLAG_SUPPORTS_CREATE)   // TODO:
    row.add(DocumentsContract.Root.COLUMN_DOCUMENT_ID, ROOT_DOCUMENT_ID)
    return result
}

override fun queryChildDocuments(
    parentDocumentId: String?,
    projection: Array<out String>?,
    sortOrder: String?
): Cursor {
    // TODO: Likely need to be more strict about projection (ie: map to supported)
    val result = MatrixCursor(projection ?: DEFAULT_DOCUMENT_PROJECTION)
    val dropboxPath = if (parentDocumentId == ROOT_DOCUMENT_ID) "" else parentDocumentId

    try {
        val client = DropboxClientFactory.client

        var childFolders = client.files().listFolder(dropboxPath)
        while (true) {
            for (metadata in childFolders.entries) {
                addDocumentRow(result, metadata)
            }

            if (!childFolders.hasMore) {
                break
            }

            childFolders = client.files().listFolderContinue(childFolders.cursor)
        }
    } catch(e: IllegalStateException) { // Test if we can attempt auth thru the provider
        context?.let {
            Auth.startOAuth2Authentication(it, appKey)   // TODO: appKey
        }
    }
    return result
}

override fun queryDocument(documentId: String?, projection: Array<out String>?): Cursor {
    // TODO: Likely need to be more strict about projection (ie: map to supported)
    val result = MatrixCursor(projection ?: DEFAULT_DOCUMENT_PROJECTION)

    try {
        val client = DropboxClientFactory.client
        val metadata = client.files().getMetadata(documentId)
        addDocumentRow(result, metadata)
    } catch(e: IllegalStateException) { // Test if we can attempt auth thru the provider
        context?.let {
            Auth.startOAuth2Authentication(it, appKey)   // TODO: appKey
        }
    }
    return result
}

Ошибка:

java.lang.IllegalArgumentException: String 'path' does not match pattern
    at com.dropbox.core.v2.files.GetMetadataArg.<init>(GetMetadataArg.java:58)
    at com.dropbox.core.v2.files.GetMetadataArg.<init>(GetMetadataArg.java:80)
    at com.dropbox.core.v2.files.DbxUserFilesRequests.getMetadata(DbxUserFilesRequests.java:1285)
    at com.anthonymandra.cloudprovider.dropbox.DropboxProvider.queryDocument(DropboxProvider.kt:98)
    at android.provider.DocumentsProvider.query(DocumentsProvider.java:797)
    at android.content.ContentProvider$Transport.query(ContentProvider.java:240)
    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:102)
    at android.os.Binder.execTransact(Binder.java:731)

path - это ROOT_DOCUMENT_ID, который я ожидаю сначала перейти к queryChildDocuments.

Что мне здесь не хватает?

1 Ответ

1 голос
/ 07 апреля 2019

Документация для реализации DocumentsProvider ограничена. В частности, нет документированной гарантии порядка звонков. Таким образом, DocumentsProvider действительно должен быть реализован, чтобы сделать как можно меньше предположений о порядке этих вызовов.

Например, я бы не предположил, что queryRoots() вызывается первым. Вероятно, это будет первым, если первым использованием DocumentsProvider для этого процесса окажется пользовательский интерфейс Storage Access Framework. Однако, учитывая, что клиенты могут (с осторожностью) сохранять документ или дерево документов Uri, вы можете вначале вызвать вас с чем-то другим в вашем процессе, если первым делом окажется клиент, использующий постоянный Uri.

И, в вашем конкретном случае, я бы не предположил, что queryChildDocuments() происходит до или после queryDocument().

...