Android调用DocumentsContract.moveDocument()所需的authority是什么?
问题描述
在应用getExternalFilesDir对应目录或用户选定的文件夹下存放文件时,创建子文件夹后调用moveDocument()将父文件夹中的文件移动到新建子文件夹,操作失败。
Logcat输出报错如下:
W/DocumentsContract: Failed to move document java.lang.IllegalArgumentException: Unknown authority at android.content.ContentResolver.call(ContentResolver.java:2412) at android.provider.DocumentsContract.moveDocument(DocumentsContract.java:1520)
排查现象:对两个关联的DocumentFile调用.getUri().getAuthority()方法,返回值均为空字符串。
调用moveDocument的代码如下:
// file and subfolder are under the same parent DocumentsContract.moveDocument(context.getContentResolver(), file.getUri(), subfolder.getParentFile().getUri(), subfolder.getUri());
补充说明:两个DocumentFile均真实存在,可正常在该子文件夹内创建文件,但无法将父文件夹下的目标文件移动到子目录中。
相关初始化代码与内部存储路径Uri如下:
// if user selected DocumentFile dir = DocumentFile.fromTreeUri(context, persistedUri); // if 'internal' DocumentFile dir = DocumentFile.fromFile(getContext().getExternalFilesDir(null)); DocumentFile subfolder = dir.createDirectory(name); DocumentFile file = dir.createFile("video/mp4", vidname); // Uris internal file:///storage/emulated/0/Android/data/com.foo.bar/files/ file:///storage/emulated/0/Android/data/com.foo.bar/files/vid file:///storage/emulated/0/Android/data/com.foo.bar/files/1656602728866.mp4
故障原因
DocumentsContract.moveDocument()仅支持处理 DocumentsProvider 提供的 content:// 格式Uri,不支持file://开头的本地文件路径Uri。- 使用
DocumentFile.fromFile()包装getExternalFilesDir()返回的普通文件路径生成的DocumentFile实例,对应Uri为file://开头,这类Uri没有authority字段,调用移动方法时会直接抛出Unknown authority异常。 - 仅通过
DocumentFile.fromTreeUri()获取的、基于用户SAF授权目录树生成的DocumentFile,才会返回带合法authority的content://Uri,可正常适配DocumentsContract系列操作接口。
修复方案
不要对所有来源的DocumentFile统一调用DocumentsContract.moveDocument(),按文件来源分场景处理:
- 操作
getExternalFilesDir等应用私有目录下的文件时,直接使用标准Java文件API完成移动,无需走SAF逻辑:
File source = new File(file.getUri().getPath()); File target = new File(subfolder.getUri().getPath(), source.getName()); source.renameTo(target);
- 操作用户通过SAF选定的公共目录文件时,再调用
DocumentsContract.moveDocument(),此时传入的Uri均为带合法authority的content://格式,可正常执行。 - 通用适配逻辑:移动操作前先判断Uri的scheme,
file开头走普通文件IO,content开头走SAF接口即可。
内容的提问来源于stack exchange,提问作者NikkyD
相关产品推荐
相关产品推荐

