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

背景

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

我成功地请求并持久许可SD卡,并且我可以列出授予许可活动返回的根Uri中的文件。

有关如何在这里完成的更多信息: 如何使用新的SD卡访问API显示为棒棒糖

然后用户可以select任何文件夹/子文件夹进行同步,并将文件夹文档Uri作为string保存在数据库中。

问题

稍后,可能在应用程序重新启动之后,可以启动文件同步。 然后我尝试列出子文件夹中的文件(请记住,我有正确的权限授予和持久性的这种作品,也授予我访问所有的孩子)。

然后,我从存储的string中创build一个DocumentFile的新实例,并尝试列出这些文件:

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

问题是listFiles总是返回根Uri授予的子项,从来没有实际Uri的子项我给DocumentFile.fromTreeUri方法。

我已经检查了DocumentFile的源代码,似乎有一个错误,具体我没有看到需要进一步修改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的来源,我们看到重buildUri:

  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); } 

通过getTreeDocumentIdfind的文档Id将始终对应于根Uri id,无论调用哪个Uri方法。 这使得使用提供的框架方法列出子文件夹的子项是不可能的。

请修复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(); 

Solutions Collecting From Web of "在Lollipop上使用Android存储访问框架列出文件时出现问题"