如何实现一个文件选择器,并且可以实际访问下载或文档文件夹中所需的文件Android(Kotlin)API 33+?

kulphzqa  于 2023-05-12  发布在  Android
关注(0)|答案(1)|浏览(193)

我正试图为我的小企业(只有3人)创建一个应用程序,允许用户(我)选择一个csv文件,让它转换数据,并将其保存为新的csv。我能够成功地从我直接带入android studio的文件中读取和操作数据,我有一个工作文件选择器,可以访问最近的文档。但是,我无法选择文档或下载文件夹中的任何文件。如能提供帮助将不胜感激。
编辑:添加了额外的代码,并澄清了我有问题的部分。
下面是我的文件选择器的代码。我会完全诚实地说,我在网上找到了大部分代码,并不完全确切地说它是如何工作的,因为大多数Android文档和示例都显示了弃用的版本

private var uriToFile:String = "Path"


    private var fileImportCompletionHandler: (Uri.()->Unit)? = null

    private val fileImportIntentLauncher =
        registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ) { result: ActivityResult ->

            if (result.resultCode == Activity.RESULT_OK) {

                val intent = result.data
                intent?.data?.let { uri ->

                    Log.i("MYTAG","uri at first check is $uri")
                    fileImportCompletionHandler?.invoke(uri) ?: run {
                        // TODO() warn

                    }

                    fileImportCompletionHandler = null
                   val p = uri.path
                    Log.i("MYTAG","p is $p")
                    

                } ?: run {
                    // TODO() warn

                }

            }
            else {
                // TODO() warn
            }

        }

    private val importIntent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {

        addCategory(Intent.CATEGORY_OPENABLE)
        type = "text/csv"

    }

fun showActionOpenDocument(completion: Uri.()->Unit) {

        fileImportCompletionHandler = completion
        fileImportIntentLauncher.launch(importIntent)

    }

这就是我所说的

binding.btnImport.setOnClickListener {
            //requestPermission()
            showActionOpenDocument {
                uriToFile = this.toString()
                binding.tvPath.text = uriToFile
            }

下面是我如何调用read(在别处完成的实际计算和操作)

fun readCSV(path:String): BufferedReader {
        val inputStream: InputStream? = contentResolver.openInputStream(Uri.parse(path))
        //return BufferedReader(InputStreamReader(assets.open("Test.csv")))

        return BufferedReader(InputStreamReader(inputStream))

    }

下面是android清单中的权限部分。我实际上并不需要访问相机,但是请求权限对话框甚至没有显示存储权限,所以我正在检查是否有不同的权限。是的

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />

这里是所有实际的权限的东西(我已经交换了所有的权限。相机是唯一的权限,甚至会弹出

private val requestPermissionLauncher =
    registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { isGranted: Boolean ->
        if (isGranted) {
            // Permission is granted. Continue the action or workflow in your
            // app.
            Log.i("MYTAG", "isGranted = true")

        } else {
            // Explain to the user that the feature is unavailable because the
            // feature requires a permission that the user has denied. At the
            // same time, respect the user's decision. Don't link to system
            // settings in an effort to convince the user to change their

        }
    }

fun requestPermission(){
    when{
        ContextCompat.checkSelfPermission(
            vContext,
            Manifest.permission.READ_EXTERNAL_STORAGE
        ) == PackageManager.PERMISSION_GRANTED -> {
            //Permission is Granted

            Log.i("MYTAG","Permission Granted")

        }
        ActivityCompat.shouldShowRequestPermissionRationale(
            vActivity,
            Manifest.permission.READ_EXTERNAL_STORAGE
        ) -> {
            //Permission denied : Additional Rational should be displayed
            Log.i("MYTAG","Permission Denied")
            showRationaleDialog("TCG Inventory Converter",
                "TCG Inventory Converter needs access to your External Storage"+
                        "\n"+"\n"+"REASON: Required to import and export CSV Files ")

        }
        else -> {
            // Permission has not been asked yet
            Log.i("MYTAG","Permission Requested")
            requestPermissionLauncher.launch(
                Manifest.permission.READ_EXTERNAL_STORAGE
            )
        }
    }
}

private fun showRationaleDialog(title:String, message:String){
    val builder: AlertDialog.Builder = AlertDialog.Builder(vContext)
    builder.setTitle(title)
        .setMessage(message)
        .setPositiveButton("Cancel"){ dialog, _->
         dialog.dismiss()
        }
        .setNegativeButton("Open Permissions"){ dialog, _ ->
            dialog.run {
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                val uri = Uri.fromParts("package","com.example.filereadtest",null)
                intent.data =uri
                startActivity(intent)
            }

        }
    builder.create().show()
}

Image of non selectable file that I want selectable
Image of only selectable location I can find (can't save files here)

k4emjkb1

k4emjkb11#

ContentResolver上调用openInputStream(),以获取Uri标识的内容上的InputStream

intent?.data?.let { uri ->
  contentResolver.openInputStream(uri).use { stream ->
    // do something useful
  }
}

理想情况下,您应该将Uri交给一个视图模型或其他可以在后台线程上执行内容I/O的东西。

相关问题