Android 作为首选项存储和检索外部存储路径的正确方法

Android 作为首选项存储和检索外部存储路径的正确方法,android,Android,我想向应用程序用户询问应用程序应该存储一些文件的路径,这些文件应该存储在首选项中,以便我可以随时访问此目录。目前,我通过一个intent请求文件夹,然后将URI存储为字符串,当我编写文件时,我将字符串转换回URI,并使用fromTreeUri创建文件(下面的代码片段) 在我重新启动应用程序之前,此功能一直有效。然后我得到一个错误: W/DocumentsContract: Failed to create document java.lang.SecurityException: Per

我想向应用程序用户询问应用程序应该存储一些文件的路径,这些文件应该存储在首选项中,以便我可以随时访问此目录。目前,我通过一个intent请求文件夹,然后将URI存储为字符串,当我编写文件时,我将字符串转换回URI,并使用
fromTreeUri
创建文件(下面的代码片段)

在我重新启动应用程序之前,此功能一直有效。然后我得到一个错误:

W/DocumentsContract: Failed to create document
    java.lang.SecurityException: Permission Denial: opening provider com.android.externalstorage.ExternalStorageProvider from ProcessRecord{92157d9 9222:xxxx} (pid=9222, uid=10310) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs
我知道这是因为权限系统,但我找不到关于如何使用它的匹配文档。我知道其他应用程序都有此功能,它们不会在每次应用程序启动时请求用户确认

获取目录URI:

private fun selectDirectory(){
val i=意图(意图.行动\打开\文档\树)
i、 addCategory(意图.类别\默认值)
startActivityForResult(Intent.createChooser(i,“选择目录”),请求\目标\文件夹)
}
重写activityResult(请求代码:Int,结果代码:Int,数据:Intent?){
super.onActivityResult(请求代码、结果代码、数据)
何时(请求代码){
请求\目标\文件夹->{
if(data==null | | data.data==null | | data.data==Uri.EMPTY){
Log.d(标记“无效URI,获取了带有数据${data?.data}的意图$data”)
返回
}否则{
val targetDir=data.data.toString()
val sharedPref=PreferenceManager.getDefaultSharedPreferences(requireContext())
sharedPref.edit().putString(
resources.getString(R.string.settings\u storage\u目录),
targetDir
).apply()
}
}
}
}
在活动中的函数内创建文档:

//这是活动,baseDir将首选项中的值作为字符串
val file=“test.jpg”
val mime=“图像/jpeg”
val document=DocumentFile.fromTreeUri(this,Uri.parse(baseDir))?.createFile(mime,file)

这是如何正确完成的?

多亏了Commonware和blackapps的评论,我才得以修复它:

private fun selectDirectory(){
val i=意图(意图.行动\打开\文档\树)
i、 addCategory(意图.类别\默认值)
//此行用于请求持久URI权限
i、 addFlags(Intent.FLAG\u GRANT\u PERSISTABLE\u URI\u权限)
startActivityForResult(Intent.createChooser(i,“选择目录”),请求\目标\文件夹)
}
重写activityResult(请求代码:Int,结果代码:Int,数据:Intent?){
super.onActivityResult(请求代码、结果代码、数据)
何时(请求代码){
请求\目标\文件夹->{
if(data==null | | data.data==null | | data.data==Uri.EMPTY){
Log.d(标记“无效URI,获取了带有数据${data?.data}的意图$data”)
返回
}否则{
//此行用于获取持久URI权限
contentResolver.takePersistableUriPermission(data.data!!,Intent.FLAG\授予\读取\ URI\权限+Intent.FLAG\授予\写入\ URI\权限)
val targetDir=data.data.toString()
val sharedPref=PreferenceManager.getDefaultSharedPreferences(requireContext())
sharedPref.edit().putString(
resources.getString(R.string.settings\u storage\u目录),
targetDir
).apply()
}
}
}
}

您应该在onActivityResult中获得持久uri权限,以便以后使用获得的uri。很好,谢谢大家!