Android Can';t将Uri转换为字符串,并再次将字符串转换为Uri

Android Can';t将Uri转换为字符串,并再次将字符串转换为Uri,android,kotlin,storage-access-framework,documentfile,Android,Kotlin,Storage Access Framework,Documentfile,我正在开发一款音乐播放器,希望使用Storage access framework访问存储器中的文件。为此,我使用了Intent.ACTION\u OPEN\u DOCUMENT\u TREE和contentResolver.takePersistableUriPermission(…)。但是一旦我获得了权限,我就必须存储允许的路径,因此我将使用SharedReferences 当我将从Intent.ACTION\u OPEN\u DOCUMENT\u TREE获得的URI转换为字符串以重用它时

我正在开发一款音乐播放器,希望使用Storage access framework访问存储器中的文件。为此,我使用了
Intent.ACTION\u OPEN\u DOCUMENT\u TREE
contentResolver.takePersistableUriPermission(…)
。但是一旦我获得了权限,我就必须存储允许的路径,因此我将使用
SharedReferences

当我将从
Intent.ACTION\u OPEN\u DOCUMENT\u TREE
获得的URI转换为字符串以重用它时,它会给我一个
nullPointerException
(它表示我从首选项转换字符串得到的URI是
null

如果我使用相同的URI而不保存到
SharedReferences
,它就可以正常工作

代码如下:

package com.gaurav712.music

import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.documentfile.provider.DocumentFile

class MainActivity : AppCompatActivity() {

    private val openDocumentTreeRequestCode: Int = 40
    private lateinit var setPreferences: SharedPreferences
    private lateinit var rootUri: Uri

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        setPreferences = getPreferences(Context.MODE_PRIVATE)

        // Check if access to storage is permitted
        checkAccess()

        // Now that we have access to storage, set the root Uri
        rootUri = Uri.parse(setPreferences.getString("allowed_path", ""))
        Log.i("rootUri", rootUri.toString())

//        listFiles()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if(requestCode == openDocumentTreeRequestCode && resultCode == RESULT_OK) {

            val treeUri = data?.data    // get data

            if (treeUri != null) {
                contentResolver.takePersistableUriPermission(treeUri,
                    Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
            }

            val editor = setPreferences.edit()
            editor.putBoolean("got_permissions", true)
            editor.putString("allowed_path", treeUri?.toString())
            editor.apply()

            Log.i("treeUri", treeUri.toString())

            val documentFile = treeUri?.let { DocumentFile.fromTreeUri(this, it) }

            for (file in documentFile?.listFiles()!!) {
                file.name?.let { Log.i("file: ", it) }
            }
        }
    }

    private fun checkAccess() {
        val gotPermission: Boolean = setPreferences.getBoolean("got_permissions", false)
        if (!gotPermission)
            getAccess()
        else
            Log.i("got_permissions",
                gotPermission.toString()
                        + " : "
                        + setPreferences.getString("allowed_path", ""))
    }

    private fun getAccess() {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
        startActivityForResult(intent, openDocumentTreeRequestCode)
    }

    private fun listFiles() {

        val documentFile: DocumentFile = DocumentFile.fromTreeUri(this, rootUri)!!

        for (file in documentFile.listFiles()) {
            Log.i("file: ", file.name.toString())
        }
    }
}
onCreate()
中,如果我取消注释
listFiles()
,它会给出
nullPointerException
,但使用与上面在
onActivityResult()
中看到的相同的代码块,这一切都可以正常工作。我要说的是:

            val documentFile = treeUri?.let { DocumentFile.fromTreeUri(this, it) }

            for (file in documentFile?.listFiles()!!) {
                file.name?.let { Log.i("file: ", it) }
            }
我不明白为什么它说
rootUri
为空


我看了所有类似的问题。我正在使用建议的相同函数(
toString()
Uri.parse
)进行转换,但它似乎不适用于存储访问框架。

我解决了它!函数
getAccess()
应该是:

    private fun getAccess() {
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
            addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
        }
        startActivityForResult(intent, openDocumentTreeRequestCode)
    }

我缺少
Intent.FLAG\u GRANT\u PERSISTABLE\u URI\u PERMISSION
Intent中的标志。

如果查看实际的
SharedReferences
XML文件(例如,通过Android Studio中的设备文件资源管理器),或者查看
setPreferences.getString(“允许的路径”)
返回的值,看起来还好吗?是的,我确认了数值。两者完全相同。我在运行时得到的Uri和我正在从
共享引用
中检索的Uri(在
toString
之后应用于我从
Intent.ACTION\u OPEN\u DOCUMENT\u TREE
中得到的
Uri
)。你能将值粘贴到这里吗?如果它是相同的
Uri
,我无法理解为什么
Uri.parse()
将无法解析它。
content://com.android.externalstorage.documents/tree/primary%3A
当我选择内部存储的根目录时。我只需将
val rootUri=Uri.parse(“content://com.android.externalstorage.documents/tree/primary%3A")
进入废弃项目,并且
rootUri
是有效的
Uri
,而不是
null