在 Lollipop 上使用 Android 存储访问框架列出文件时出现错误

2024-03-03

背景

我有一些应用程序大量使用 SD 卡进行文件同步。 Kitkat 上的外部 SD 卡访问损坏仍然是一个大问题,但我正在尝试使用 Lollipop 上提供的新 API 为拥有此问题的用户解决此问题。

我成功请求并保留了对 SD 卡的权限,并且我可以列出从授予权限活动返回的根 Uri 中的文件。

请在此处查看有关如何完成此操作的更多信息:如何使用棒棒糖的新 SD 卡访问 api https://stackoverflow.com/questions/26744842/how-to-use-the-new-sd-card-access-api-presented-for-lollipop

然后,用户可以选择任何文件夹/子文件夹进行同步,我将文件夹文档 Uri 作为字符串保留在数据库中。

Problem

稍后,可能在应用程序重新启动后,可以启动文件同步。然后,我尝试列出子文件夹中的文件(请记住,我已授予正确的权限,并且该权限有效,并且还允许我访问所有子文件夹)。

然后,我从存储的字符串创建一个新的 DocumentFile 实例并尝试列出文件:

  DocumentFile dir = DocumentFile.fromTreeUri(ctx, Uri.parse(storedUri));
  dir.listFiles();

问题是 listFiles 总是返回授予的根 Uri 的子级,而不返回我给 DocumentFile.fromTreeUri 方法的实际 Uri 的子级。

我已经检查了源代码文档文件 http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.0_r1/android/support/v4/provider/DocumentFile.java那里似乎有一个错误,特别是我认为不需要进一步修改 Uri:

public static DocumentFile fromTreeUri(Context context, Uri treeUri) {
  final int version = Build.VERSION.SDK_INT;
  if (version >= 21) {
    return new TreeDocumentFile(null, context,
      DocumentsContractApi21.prepareTreeUri(treeUri));
  } else {
  return null;
}

如果我们查看 DocumentsContractApi21.prepareTreeUri 的源代码,我们会看到重建了 Uri:

 public static Uri prepareTreeUri(Uri treeUri) {
   return DocumentsContract.buildDocumentUriUsingTree(treeUri,
     DocumentsContract.getTreeDocumentId(treeUri));
 }

以及它调用的方法:

 public static Uri buildDocumentUriUsingTree(Uri treeUri, String documentId) {
   return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
                 .authority(treeUri.getAuthority()).appendPath(PATH_TREE)
                 .appendPath(getTreeDocumentId(treeUri)).appendPath(PATH_DOCUMENT)
                 .appendPath(documentId).build();
 }

 public static String getTreeDocumentId(Uri documentUri) {
   final List<String> paths = documentUri.getPathSegments();
   if (paths.size() >= 2 && PATH_TREE.equals(paths.get(0))) {
     return paths.get(1);
   }
   throw new IllegalArgumentException("Invalid URI: " + documentUri);
 }

通过 getTreeDocumentId 找到的文档 Id 将始终对应于根 Uri id,无论使用什么 Uri 调用方法。这使得无法使用提供的框架方法列出子文件夹的子文件夹。

Solution

请修复 fromTreeUri 方法,使其不总是使用根文档 Uri id。

执行以下丑陋的黑客解决了这个问题,我真的不想这样做。

  Class<?> c = Class.forName("android.support.v4.provider.TreeDocumentFile");
  Constructor<?> constructor = c.getDeclaredConstructor(DocumentFile.class, Context.class, Uri.class);
  constructor.setAccessible(true);

  DocumenFile dir = (DocumentFile) constructor.newInstance(null, mCtx, treeUri);
  dir.listFiles();

潜在的错误似乎已得到修复。我也遇到了这个问题,无需任何代码更改,它现在可以在 1.0.1 版本中使用documentfile包裹。

dependencies {
    ...
    implementation 'androidx.documentfile:documentfile:1.0.1'
    ...
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Lollipop 上使用 Android 存储访问框架列出文件时出现错误 的相关文章

随机推荐

  • Rails 3 在“lib”目录中看不到我的类

    我已放置文件rack app rb与简单的机架应用程序lib目录 class RackApp def call env 200 Hello end end 然后我添加了这条路线 match rack gt RackApp 当我尝试启动 Ra
  • 从 PDF 文件中提取文本数据

    是否可以在 R 中解析 PDF 文件中的文本数据 那里似乎不是此类提取的相关包 http crantastic org search q parse pdf 但是有人尝试过或见过 R 中这样做吗 In Python中有PDFMiner ht
  • 如何查明 Prolog 是否执行尾调用优化

    使用SWI Prolog Win x64 的开发版本 我为 a 编写了一个 DCG 谓词确定性词法分析器 托管在 github 上 https github com sebgod goldparser prolog 因此所有外部谓词都没有留
  • 在 Perl 中获取按修改日期排序的文件列表

    我正在尝试获取按修改日期排序的文件列表 我修改了示例程序根据日期和时间对目录进行排序并列出文件 http forums devshed com perl programming 6 sort directory and list files
  • 使用loopj Android异步Http客户端同步调用

    在一种情况下 我尝试在 Loopj 上使用 setUseSynchronousMode 来等待 http 调用的结果 然后再继续 我试过 AsyncHttpResponseHandler responseHandler new AsyncH
  • 如何尽可能快地生成此 switch 语句?

    2009 12 04 更新 有关此处发布的一些建议的分析结果 请参见下文 问题 考虑以下非常无害 非常简单的方法 它使用switch返回定义的枚举值的语句 public static MarketDataExchange GetMarket
  • 单元测试项目中的连接字符串到 app_data 文件夹中的引用数据库

    我希望在单元测试项目中引用我的数据库文件 这是一个 ASP NET MVC 应用程序 请注意 我知道我不应该在单元测试中访问数据库 但这是为了快速修复我现在需要通过的一项测试 在下一个里程碑之后 我将嘲笑数据库访问方法等 这是我的 mvc
  • 在 Groovy 1.7 中使用具有混合内容的 HTML 构建器的正确语法是什么?

    On the Groovy 示例页面 https web archive org web 20100712132418 http groovy codehaus org Builders有一个示例说明如何使用具有混合内容的 Groovy H
  • Android:使用自定义键盘编辑文本

    我按照 sdk 中的示例创建了自己的自定义键盘 现在我想在我的应用程序中的 EditText 上默认使用这个自定义键盘 实际上我必须长按 edittext 然后选择我的custom keyboard 我怎样才能做到这一点 似乎与 input
  • 猜测无界整数

    如果我对你说 我正在想一个0到n之间的数字 我会告诉你你的猜测是高还是低 然后你会立即进行二分查找 如果我删除上限怎么办 即我正在考虑一个正整数 你需要猜测它 一种可能的方法是让您猜测 2 4 8 直到您对某些 k 猜测 2 k 并且我说
  • Pod 无法安装软件包(apt-get update 或 apt-get install )

    我发现集群中的 pod 在 exec 到 pod 时无法安装软件包 在调试时我意识到这是由于 etc resolv conf entries The etc resolv conf 其中一个 Pod 的条目是 nameserver 192
  • XMPP 带有支持 X-FACEBOOK-PLATFORM 的 Java Asmack 库

    我正在尝试使用 Smack 库在 Android 上进行 Facebook 聊天 我读过Chat API http developers facebook com docs chat 来自 Facebook 但我不明白如何使用这个库向 Fa
  • 对部分排序的数组进行排序

    我正在尝试对具有以下属性的数组进行排序 它增加到一定程度然后开始减少 然后增加然后减少等等 是否有任何算法可以通过利用部分排序来以低于 nlog n 的复杂度对其进行排序 数组示例 14 19 34 56 36 22 20 7 45 56
  • Python 求和字典列表中元组中的值?

    在我的字典中 每个条目都有一个元组列表 我的python语法可能是错误的 请耐心等待 它看起来像这样 1 2 2 4 3 6 1 7 1 8 3 2 4 1 5 3 1 2 我想对每个条目的元组中的第二个值求和 即 1 10 2 5 我一直
  • 当 TabHost 存在于活动中时,EditText 使用硬键盘失去焦点

    我正在 tabhost 内显示 EditText Tabhost 位于 SherlockFragmentActivity 内部 假设我处于触摸模式 我单击 EditText 以使其获得焦点并开始在其上输入内容 输入 2 3 个字符后 我决定
  • 将 image/jpeg 作为 arraybuffer 或 blob 返回

    我目前正在调用我的 api 它返回一个图像作为image jpeg 我的问题是通过 javascript Angular 调用 url 时 factory资源 我的数组缓冲区为空 另外 字节长度为 0 如果我使用响应类型 或 文本 调用 a
  • 是否有专为创建 REST API 参考文档而设计的 CMS 引擎? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Scala 并行赋值仅在声明中

    Having def f 1 two 3 0 为什么可以 var x y z f but not var i 0 var j hello var k 0 0 use i j k then i j k f expected but found
  • 用于未来更新的 Android 数据库方法

    在 android 中使用 sqlite 数据库的最佳方法是什么 sqlite数据库文件 第一次复制到应用环境中 OR 在代码中创建表 在数据库助手的 onCreate 中 我的数据库有6个表 第一次是空的 我问这个问题是因为我想将来更新我
  • 在 Lollipop 上使用 Android 存储访问框架列出文件时出现错误

    背景 我有一些应用程序大量使用 SD 卡进行文件同步 Kitkat 上的外部 SD 卡访问损坏仍然是一个大问题 但我正在尝试使用 Lollipop 上提供的新 API 为拥有此问题的用户解决此问题 我成功请求并保留了对 SD 卡的权限 并且