在Lollipop上使用Android Storage Access框架列出文件时出现错误 [英] Bug when listing files with Android Storage Access framework on Lollipop

查看:103
本文介绍了在Lollipop上使用Android Storage Access框架列出文件时出现错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

我有一些应用程序大量使用SD卡进行文件同步. Kitkat上的外部SD卡访问中断仍然是一个大问题,但是我正尝试使用Lollipop上针对有此功能的用户可用的新API来解决此问题.

I have a few apps that make heavy use of SD card for file syncing. The broken external SD card access on Kitkat is still a big problem, but I am trying to resolve this with the new API available on Lollipop for the users which have this.

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

I successfully request and persist permission to SD card and I can list files in the root Uri returned from the grant permission activity.

在此处查看有关此操作的更多信息: how-to-use-the-为棒棒糖呈现的新SD卡访问API

See more info on how this is done here: how-to-use-the-new-sd-card-access-api-presented-for-lollipop

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

The user can then select any folder/subfolder for sync and I persist the folder document Uri as a string in the database.

问题

稍后,可能在重新启动应用程序之后,可以开始文件同步.然后,我尝试在子文件夹中列出文件(请记住,我已经获得了正确的权限,并且这种工作的持久性也使我可以访问所有子项).

Later, potentially after app has been restarted, the syncing of files can initiate. I then try to list the files in a subfolder (remember, I have the right permission granted and the persistence of this works and also grants me access to all children).

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

I then create a new instance of DocumentFile from the stored string and try to list the files:

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

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

The problem is listFiles always returns the children at the root Uri granted and never the children of the actual Uri I give the DocumentFile.fromTreeUri method.

我已经检查了

I have examined the source code of DocumentFile and it seems there is a bug there, specifically I don't see the need to modify the Uri further:

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:

If we look at the source of DocumentsContractApi21.prepareTreeUri we see that rebuilds the 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.这样就无法使用提供的框架方法列出子文件夹的子级.

The found document Id by getTreeDocumentId will always correspond to the root Uri id, no matter what Uri the methods is called with. This makes it impossible to list children of sub folders using the provided framework methods.

解决方案

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

Please fix the fromTreeUri method to not always use the root document Uri id.

进行以下丑陋修改即可解决此问题,我真的不希望这样做.

Doing the following ugly hack fixes the issue, which I would really prefer not to.

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

推荐答案

潜在的错误似乎已修复.我也遇到了这个问题,并且没有任何代码更改,现在它可以在documentfile软件包的1.0.1版本中使用.

The underlying bug seems to be fixed. I also encountered that problem and without any code changes it works now with version 1.0.1 of the documentfile package.

dependencies {
    ...
    implementation 'androidx.documentfile:documentfile:1.0.1'
    ...
}

这篇关于在Lollipop上使用Android Storage Access框架列出文件时出现错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆