Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/190.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Android首选项中正确接收和存储本地目录/路径?_Android_Kotlin - Fatal编程技术网

如何在Android首选项中正确接收和存储本地目录/路径?

如何在Android首选项中正确接收和存储本地目录/路径?,android,kotlin,Android,Kotlin,我想存储一个本地路径(内部或外部存储),用户可以将一些数据作为首选项存储在Android应用程序中。我希望用户在首选项中选择首选文件夹。默认文件夹是context.externalMediaDirs,它返回一个文件对象,该对象的绝对路径是我在SharedReferences中存储为字符串的。稍后,当用户保存数据时,数据将通过FileOutputStream正确存储到该文件夹中新创建的文件中 现在,我在首选项中添加了一个打开文档树的意图,以便用户可以选择不同的文件夹。但是intent以conten

我想存储一个本地路径(内部或外部存储),用户可以将一些数据作为首选项存储在Android应用程序中。我希望用户在首选项中选择首选文件夹。默认文件夹是
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)