【问题标题】:How to filter the results of a query with buildChildDocumentsUriUsingTree如何使用 buildChildDocumentsUriUsingTree 过滤查询结果
【发布时间】:2019-03-17 03:12:47
【问题描述】:

我想将文件保存在 SD 卡文件夹中。

而且我不能在我的项目中使用 V4 支持。

所以我打电话:

Intent itent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
itent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
itent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(itent, requestCodeTree);

然后在 onActivityResult 上,我有:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);

    if (resultCode == RESULT_OK) {
        switch(requestCode) {
            case requestCodeTree:
                saveFile(intent.getData());
                break;
        }
    }
}

saveFile 的代码是:

   private void saveFile(Uri data) {
        ContentResolver contentResolver = context.getContentResolver();

        InputStream in = null;
        OutputStream out = null;

        try {

            // Problems start here ************************
            Uri toUriFile= getUriBackupFile(context, data);
            // ********************************************

            if (toUriFile==null) {
                Uri toUriFolder = DocumentsContract.buildDocumentUriUsingTree(data, DocumentsContract.getTreeDocumentId(data));
                toUriFile = DocumentsContract.createDocument(contentResolver, toUriFolder, "", backupName);
            }

            out = contentResolver.openOutputStream(toUriFile);
            in = new FileInputStream(fromFile);

            byte[] buffer = new byte[1024];
            int read;
            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);
            }
            in.close();
            // write the output file (the file is now copied)
            out.flush();
            out.close();

        } catch (FileNotFoundException e) {
            Log.e(TAG, "Failed", e);
        } catch (Exception e) {
            Log.e(TAG, "Failed", e);
        }
    }

到目前为止一切顺利。

当我调用 getUriBackupFile 来获取目标文件的 uri 时,问题就开始了。

为此,我使用 buildChildDocumentsUriUsingTree 查询 ContentResolver 并尝试过滤 DocumentsContract.Document.COLUMN_DISPLAY_NAME 与我的文件显示匹配的结果名字,像这样:

private static Uri getUriBackupFile(Context context, Uri treeUri) {
        final ContentResolver resolver = context.getContentResolver();

        final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(
                treeUri,
                DocumentsContract.getTreeDocumentId(treeUri));

        Cursor c = null;
        try {
            String[] projections = new String[] {
                    DocumentsContract.Document.COLUMN_DOCUMENT_ID,
                    DocumentsContract.Document.COLUMN_DISPLAY_NAME};

            // this line doesn't seem to have any effect !
        String selection = DocumentsContract.Document.COLUMN_DISPLAY_NAME + " = '" + backupName + "' ";
            // *************************************************************************

            c = resolver.query(childrenUri, projections, selection, null, null);

            if (c!=null && c.moveToFirst()) {
            // Here I expect to have c.getCount() == 1 or == 0
            // But actually c.getCount() == [Number of children in the treeUri] regardless of the selection
                String documentId = c.getString(0);
                Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(treeUri,
                        documentId);
                return documentUri;
            }

        } catch (Exception e) {
            Log.w(TAG, "Failed query: " + e);
        } finally {
            if (c!=null) c.close();
        }

        return null;
    }

但是查询总是返回 treeUri 的所有子节点,无论选择如何。所以,似乎选择没有效果。

我总是可以循环遍历所有结果,但如果所选文件夹有大量文件,则对性能不利。

所以我的问题是

  1. 如何过滤查询结果?
  2. 这是将文件保存在 sd 卡路径上的正确方法吗?

【问题讨论】:

    标签: android file save sd-card


    【解决方案1】:

    【讨论】:

    • +1 不幸的是,这是正确的。我不断发现DocumentsContract 的记录和实现有多么糟糕。而新的存储访问框架使其成为强制性的......
    【解决方案2】:
    1. 您需要在清单中添加读取/写入外部存储的权限。在您的应用程序标记之前添加这一行。

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    1. 如果您的应用在运行 android 6 或更高版本的设备上运行。您需要先请求许可,然后才能写入 sd 卡/外部存储。遵循this有关在运行时检查权限的文档。

    2. 使用 Environment.getExternalStorageDirectory() 获取外部目录。这将返回外部目录。

    另请参阅此documentation (https://developer.android.com/training/data-storage/files) 和this 问题。

    【讨论】:

    • 感谢您的回复。但是我的应用程序已经拥有这些权限并在运行时检查它们
    • 好的。所以要手动选择要保存文件的路径?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-28
    • 2022-10-14
    • 2021-11-24
    • 2021-11-21
    • 2012-04-20
    • 2019-12-29
    • 1970-01-01
    相关资源
    最近更新 更多