gpt4 book ai didi

android - queryRoots 首先调用 queryDocument,而不是 queryChildDocuments

转载 作者:行者123 更新时间:2023-11-29 16:30:59 24 4
gpt4 key购买 nike

我正在为 Dropbox 的 SAF 包装器编写一个包装器,因为每个人(包括 Google)都懒得实现这个“非常丰富”(即:糟糕)的 API。我的根是选择器,但我认为应该首先调用 queryChildren。但是,永远不会调用 queryChildren,它会直接转到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)

pathROOT_DOCUMENT_ID,我希望它首先转到 queryChildDocuments

我在这里错过了什么?

最佳答案

我也写了一个 SAF DropBox 实现,一开始我也有点困惑。

来自documentation :

注意以下几点:

  • 每个文档提供者报告一个或多个正在启动的“根”指向探索文档树。每个根都有一个独特的COLUMN_ROOT_ID,它指向一个文件(一个目录)表示该根目录下的内容。根是动态的旨在支持多个帐户、 transient USB 等用例存储设备,或用户登录/注销。
  • 每个根目录下都有一个文档。那个文件指向1到N文档,每个文档又可以指向 1 到 N 个文档。
  • 每个存储后端通过使用唯一的 COLUMN_DOCUMENT_ID 引用它们。文件 ID 必须是独一无二的,一旦发布就不会改变,因为它们用于跨设备重启的持久 URI 授权。
  • 文档可以是可打开的文件(具有特定的 MIME 类型),或包含附加文件的目录(带有MIME_TYPE_DIR MIME 类型)。
  • 每个文档都可以具有不同的功能,如COLUMN_FLAGS。例如,FLAG_SUPPORTS_WRITE,FLAG_SUPPORTS_DELETE 和 FLAG_SUPPORTS_THUMBNAIL。相同COLUMN_DOCUMENT_ID 可以包含在多个目录中。

第二个项目符号是关键项目符号。从 queryRoots() 返回后,对于您传回的每个根,SAF 都会调用 queryDocument()。这实质上是创建出现在列表中的“根文件夹”文件。我所做的是在 queryDocument() 中检查传入的 documentId 是否与我在 queryRoots() 调用中赋予 DocumentsContract.Root.COLUMN_ROOT_ID 的唯一值匹配。如果是,则您知道此 queryDocument() 调用需要返回代表该根目录的文件夹。否则,我在其他任何地方都使用来自 DropBox 的路径作为我的 documentId,因此我在通过 DbxClientV2 的调用中使用该 documentID 值。

这是一些示例代码 - 请注意,在我的例子中,我创建了一个 AbstractStorageProvider 类,我的所有各种提供程序(Dropbox、Instagram 等)都从该类扩展。基类处理接收来自 SAF 的调用,它会做一些内务处理(比如创建游标),然后调用实现类中的方法来根据特定服务的需要填充游标:

基类

public Cursor queryRoots(final String[] projection) {
Timber.d( "Lifecycle: queryRoots called");

// If they are not paid up, they do not get to use any of these implementations
if (!InTouchUtils.isLoginPaidSubscription()) {
return null;
}

// Create a cursor with either the requested fields, or the default projection if "projection" is null.
final MatrixCursor cursor = new MatrixCursor(projection != null ? projection : getDefaultRootProjection());

// Classes that extend this one must implement this method
addRowsToQueryRootsCursor(cursor);

return cursor;
}

来自 DropboxProvider addRowsToQueryRootsCursor:

protected void addRowsToQueryRootsCursor(MatrixCursor cursor) {
// See if we need to init
long l = System.currentTimeMillis();
if ( !InTouchUtils.initDropboxClient()) {
return;
}
Timber.d( "Time to test initialization of DropboxClient: %dms.", (System.currentTimeMillis() - l));
l = System.currentTimeMillis();
try {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(Objects.requireNonNull(getContext()).getApplicationContext());
String displayname = sharedPrefs.getString(getContext().getString(R.string.pref_dropbox_displayname_token_key),
getContext().getResources().getString(R.string.pref_dropbox_displayname_token_default));

batchSize = Long.valueOf(Objects.requireNonNull(sharedPrefs.getString(getContext().getString(R.string.pref_dropbox_query_limit_key),
getContext().getResources().getString(R.string.pref_dropbox_query_limit_key_default))));

final MatrixCursor.RowBuilder row = cursor.newRow();

row.add(DocumentsContract.Root.COLUMN_ROOT_ID, <YOUR_UNIQUE_ROOTS_KEY_HERE>);
row.add(DocumentsContract.Root.COLUMN_TITLE,
String.format(getContext().getString(R.string.dropbox_root_title),getContext().getString(R.string.app_name)));
row.add(DocumentsContract.Root.COLUMN_SUMMARY,displayname+
getContext().getResources().getString(R.string.dropbox_root_summary));
row.add(DocumentsContract.Root.COLUMN_FLAGS, DocumentsContract.Root.FLAG_SUPPORTS_RECENTS | DocumentsContract.Root.FLAG_SUPPORTS_SEARCH);
row.add(DocumentsContract.Root.COLUMN_DOCUMENT_ID,<YOUR_UNIQUE_ROOT_FOLDER_ID_HERE>);
row.add(DocumentsContract.Root.COLUMN_ICON, R.drawable.intouch_for_dropbox);
} catch (Exception e) {
Timber.d( "Called addRowsToQueryRootsCursor got exception, message was: %s", e.getMessage());
}
Timber.d( "Time to queryRoots(): %dms.", (System.currentTimeMillis() - l));
}

然后基类中的queryDocument()方法:

@Override
public Cursor queryDocument(final String documentId, final String[] projection) {
Timber.d( "Lifecycle: queryDocument called for: %s", documentId);

// Create a cursor with either the requested fields, or the default projection if "projection" is null.
// Return a cursor with a getExtras() method, to avoid the immutable ArrayMap problem.
final MatrixCursor cursor = new MatrixCursor(projection != null ? projection : getDefaultDocumentProjection()){
Bundle cursorExtras = new Bundle();
@Override
public Bundle getExtras() {
return cursorExtras;

}
};
addRowToQueryDocumentCursor(cursor, documentId);
return cursor;
}

和 DropboxProvider 中的 addRowToQueryDocumentCursor():

protected void addRowToQueryDocumentCursor(MatrixCursor cursor,
String documentId) {

try {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(Objects.requireNonNull(getContext()).getApplicationContext());
String displayname = sharedPrefs.getString(getContext().getString(R.string.pref_dropbox_displayname_token_key),
getContext().getString(R.string.pref_dropbox_displayname_token_default));
if ( !InTouchUtils.initDropboxClient()) {
return;
}

if ( documentId.equals(<YOUR_UNIQUE_ROOTS_ID_HERE>)) {
// root Dir
Timber.d( "addRowToQueryDocumentCursor called for the root");
final MatrixCursor.RowBuilder row = cursor.newRow();
row.add(DocumentsContract.Document.COLUMN_DOCUMENT_ID, <YOUR_UNIQUE_FOLDER_ID_HERE>);
row.add(DocumentsContract.Document.COLUMN_DISPLAY_NAME,
String.format(getContext().getString(R.string.dropbox_root_title),
getContext().getString(R.string.app_name)));
row.add(DocumentsContract.Document.COLUMN_SUMMARY,displayname+
getContext().getString(R.string.dropbox_root_summary));
row.add(DocumentsContract.Document.COLUMN_ICON, R.drawable.folder_icon_dropbox);
row.add(DocumentsContract.Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR);
row.add(DocumentsContract.Document.COLUMN_FLAGS, 0);
row.add(DocumentsContract.Document.COLUMN_SIZE, null);
row.add(DocumentsContract.Document.COLUMN_LAST_MODIFIED, null);
return;
}
Timber.d( "addRowToQueryDocumentCursor called for documentId: %s", documentId);
DbxClientV2 mDbxClient = DropboxClientFactory.getClient();
Metadata metadata = mDbxClient.files().getMetadata(documentId);

if ( metadata instanceof FolderMetadata) {
Timber.d( "Document was a folder");
includeFolder(cursor, (FolderMetadata)metadata);
} else {
Timber.d( "Document was a file");
includeFile(cursor, (FileMetadata) metadata);
}
} catch (Exception e ) {
Timber.d( "Called addRowToQueryDocumentCursor got exception, message was: %s documentId was: %s.", e.getMessage(), documentId);
}
}

关于android - queryRoots 首先调用 queryDocument,而不是 queryChildDocuments,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55560010/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com