使用DocumentsContract.createDocument时出现Invalid URI异常的问题
目录选择后创建文件报错的排查与解决
问题场景
使用Kotlin和Jetpack Compose开发Android应用,实现用户选择目录后在其中创建并写入文本文件的功能,执行目录选择操作后触发以下异常:
Failed to create document java.lang.IllegalArgumentException: Invalid URI: content://com.android.externalstorage.documents/tree/primary%3ADownload%2FTest at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:172) at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142) at android.content.ContentProviderProxy.call(ContentProviderNative.java:764) at android.content.ContentResolver.call(ContentResolver.java:2466) at android.provider.DocumentsContract.createDocument(DocumentsContract.java:1380)
问题原因
OpenDocumentTree返回的是目录的Tree URI(格式如content://.../tree/...),而DocumentsContract.createDocument方法要求传入的是目录的Document URI(格式如content://.../document/...),两者格式不匹配导致参数无效。
解决方案
将选中目录的Tree URI转换为对应的Document URI后,再调用createDocument方法。修改createFileInDirectory函数如下:
fun createFileInDirectory(context: Context, parentUri: Uri) { val contentResolver = context.contentResolver val mimeType = "text/plain" val displayName = "example.txt" try { // 将Tree URI转换为Document URI val documentId = DocumentsContract.getTreeDocumentId(parentUri) val documentUri = DocumentsContract.buildDocumentUriUsingTree(parentUri, documentId) // 在转换后的Document URI对应的目录下创建文件 val newDocumentUri = DocumentsContract.createDocument( contentResolver, documentUri, mimeType, displayName ) newDocumentUri?.let { writeToFile(context, it) } } catch (e: Exception) { Toast.makeText(context, "Error creating file: ${e.message}", Toast.LENGTH_LONG).show() } }
原理说明
- Tree URI是系统用于授予应用对整个目录树访问权限的标识,无法直接用于创建子文档
- 通过
DocumentsContract.getTreeDocumentId提取Tree URI中的文档ID,再用DocumentsContract.buildDocumentUriUsingTree构建出对应目录的Document URI,该URI代表具体的目录节点,可用于创建子文件
内容的提问来源于stack exchange,提问作者jyotesh
相关产品推荐
相关产品推荐

