如何在Android首选项中正确接收和存储本地目录/路径?
我想存储一个本地路径(内部或外部存储),用户可以将一些数据作为首选项存储在Android应用程序中。我希望用户在首选项中选择首选文件夹。默认文件夹是如何在Android首选项中正确接收和存储本地目录/路径?,android,kotlin,Android,Kotlin,我想存储一个本地路径(内部或外部存储),用户可以将一些数据作为首选项存储在Android应用程序中。我希望用户在首选项中选择首选文件夹。默认文件夹是context.externalMediaDirs,它返回一个文件对象,该对象的绝对路径是我在SharedReferences中存储为字符串的。稍后,当用户保存数据时,数据将通过FileOutputStream正确存储到该文件夹中新创建的文件中 现在,我在首选项中添加了一个打开文档树的意图,以便用户可以选择不同的文件夹。但是intent以conten
context.externalMediaDirs
,它返回一个文件
对象,该对象的绝对路径是我在SharedReferences中存储为字符串的。稍后,当用户保存数据时,数据将通过FileOutputStream正确存储到该文件夹中新创建的文件中
现在,我在首选项中添加了一个打开文档树的意图,以便用户可以选择不同的文件夹。但是intent以content://com.android.externalstorage.documents/...
我将其存储为字符串,但当我尝试通过context.contentResolver.openOutputStream()编写文件时,我得到一个错误,即我需要“管理文档”权限。但这只适用于系统应用程序
我找到了如何将URI转换为本地路径的解决方案,但人们总是注意到,这是一种不成熟的做法,不应该这样做。我尝试了contentResolver.takePersistableUriPermission(…)
,但没有任何更改
那么,从用户那里接收文件夹、将其存储在首选项中并能够在其中创建新文件的正确方法是什么呢
编辑:
当前方法
首选项XML(摘录):
结果处理(在blackapps请求中更改为不包括共享首选项,但仅创建文件)
尝试创建一个新文件,一段时间后(可能几个小时)
val targetDirPreference: Preference? = findPreference("target_dir")
targetDirPreference?.setOnPreferenceClickListener {
startActivityForResult(it.intent, REQUEST_TARGET_FOLDER)
true
}
val targetDir = PreferenceManager.getDefaultSharedPreferences(context).getString("target_dir", null)
val targetFile = "${System.currentTimeMillis()}.png"
val uri = Uri.parse("$targetDir%2F$targetFile")
val stream = context.contentResolver.openOutputStream(uri)
最后一行由于权限错误而崩溃。您无法通过简单的字符串连接创建文档
Uri
。相反:
- 使用
获取表示树的DocumentFile.fromTreeUri()
DocumentFile
- 在这一点上,调用
以获取表示要创建的内容的createFile()
DocumentFile
- 在此基础上,获取要与
openOutputStream()一起使用的
Uri
takePersistableUriPermissions()
默认文件夹是context.externalMediaDirs,它返回一个文件对象,该文件对象的绝对路径是我在SharedReferences中存储为字符串的。稍后,当用户保存数据时,数据将通过FileOutputStream正确存储到该文件夹中新创建的文件中
如果使用的是数组中的第0个索引,则可能会出现这种情况。其他代表可移动存储,如果用户更换其可移动存储(例如,交换micro SD卡),其目录名可能会更改。只有内置外部存储上的目录是稳定的。看起来您使用OPEN\u DOCUMENT\u树并获得持久权限后一切正常。当然,您甚至不应该尝试将uri(您的内容方案)转换为路径。在onActivityResult中,您应该获得持久权限并立即创建新文件夹或文件。一旦运行正常,您将在共享首选项中存储获取的内容方案,并在重新启动应用程序后创建文件夹或文件。目的是在创建文件前几天或几周运行。意图返回后,将不会创建任何文件或文件夹。这个意图应该提供一个我可以永远写文件的位置。就像为浏览器定义默认下载文件夹一样。我永远不知道下一个文件什么时候创建。所以这并不完全是关于修复我的代码,但我想知道正确的方法是什么。我已经告诉过你了。我建议在onActivityResult中创建一个文件或文件夹只是为了测试。一旦这起作用,您可以删除该代码。这只是为了测试的目的。您应该理解这一点。请重复:
,当然,您不能以尝试的方式创建文件URI代码>。情况仍然如此。val uri=uri.parse($targetDir%2F$targetFile))您的uri开头无效。您必须首先创建文件。如果你这样做了,你可以得到一个uri。
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
if ((requestCode == REQUEST_TARGET_FOLDER ) && resultCode == RESULT_OK && intent != null) {
//val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
//sharedPreferences.getString("target_dir", "")?.also {
// with(sharedPreferences.edit()) {
// putString("target_dir", intent.data.toString())
// commit()
// }
val newFile = Uri.parse("${intent.dataString}%2Ftest.png")
context?.contentResolver?.openOutputStream(newFile)
}
}
else {
super.onActivityResult(requestCode, resultCode, intent)
}
}
val targetDir = PreferenceManager.getDefaultSharedPreferences(context).getString("target_dir", null)
val targetFile = "${System.currentTimeMillis()}.png"
val uri = Uri.parse("$targetDir%2F$targetFile")
val stream = context.contentResolver.openOutputStream(uri)