使用系统对话框打开任何文件类型进行查看

Posted

技术标签:

【中文标题】使用系统对话框打开任何文件类型进行查看【英文标题】:Open any file type using the system dialog for viewing 【发布时间】:2021-09-20 17:07:03 【问题描述】:

在我的应用程序中,我希望用户能够选择他们想要的任何文件(.mp4、.pdf 等),在应用程序中显示文件名和扩展名,最后允许他们打开引用的文件使用系统对话框。我已经成功打开文件选择器对话框,获取所选文件的路径和信息,但我无法理解如何使用该文件的路径来触发将处理文件打开过程的操作系统对话框。我已经阅读了一些关于 SAF 和 ACTION_OPEN_DOCUMENT 行动的信息,但我似乎无法理解这是否有必要或如何去做。

这是我的文件检索过程:

private fun openFilePicker()  
   val intent = Intent(Intent.ACTION_GET_CONTENT)
   intent.type = "*/*"
   startActivityForResult(intent, PICKFILE_RESULT_CODE)


override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
        when (requestCode) 
            PICKFILE_RESULT_CODE -> if (resultCode == RESULT_OK) 
                val filePath: String? = data?.data?.path
                if (filePath != null) attachmentsAdapter.addFilePath(filePath) else Toast.makeText(
                    requireContext(),
                    "Something went wrong, please try again!",
                    Toast.LENGTH_SHORT
                ).show()
            
            else -> super.onActivityResult(requestCode, resultCode, data)
        
    

我知道引入 SAF 是为了改善用户的隐私,并且应用程序最初只能访问自己的目录(我认为还有一些公共目录),但我真的需要做一些事情,比如创建自己的目录、复制在那里引用文件,然后做任何我需要做的事情来打开它们?

根据 CommonsWare 的回答更新

正如 CommonsWare 所说,诀窍是简单地避免使用返回的 URI 的路径,而是使用 URI 本身。有关详细信息,请参阅他们的答案。

此外,由于我只使用文件的 URI,因此获取其名称和扩展名有点不同。以下是使用光标的方法:

private fun getFileNameWithExtensionFromUri(currentFileUri: String): String? 
    val returnCursor: Cursor? = context.contentResolver.query(Uri.parse(currentFileUri), null, null, null, null)
    /*
     * Get the column indexes of the data in the Cursor,
     * move to the first row in the Cursor, get the data,
     * and display it.
     */
    val nameIndex = returnCursor?.getColumnIndex(OpenableColumns.DISPLAY_NAME)
    returnCursor?.moveToFirst()
    val fileName = returnCursor?.getString(nameIndex!!)
    returnCursor?.close()
    return fileName

【问题讨论】:

【参考方案1】:

这是我的文件检索过程

A Uri is not a file。 data?.data?.path 通常不会返回文件系统路径。

我无法理解如何使用该文件的路径来触发将处理文件打开过程的操作系统对话框

android 没有“处理文件打开过程的操作系统对话框”,至少我会使用这些术语。

如果您想尝试打开一些可以查看内容的应用,请创建一个ACTION_VIEW Intent

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
        when (requestCode) 
            PICKFILE_RESULT_CODE -> if (resultCode == RESULT_OK) 
                data?.data?.let  uri ->
                  try 
                    startActivity(Intent(Intent.ACTION_VIEW, uri)).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                   catch (e: Exception) 
                    Toast.makeText(
                      requireContext(),
                      "Something went wrong, please try again!",
                      Toast.LENGTH_SHORT
                    ).show()
                  
                
            
            else -> super.onActivityResult(requestCode, resultCode, data)
        
    

try/catch 很重要,因为您允许用户选择任何类型的内容,并且可能没有安装支持查看该特定类型内容的应用。

【讨论】:

对于 Uri 和 File 词的误用,我很抱歉,你是对的。我今天早些时候尝试此解决方案时遇到的问题是 FileProvider。我现在正在添加更多详细信息。 @SteliosPapamichail:你不需要FileProvider。您确实需要保留整个Uri 并停止在Uri 上调用getPath()。但是,我确实忘记了添加到答案中的权限标志(对不起!)。 您再次正确,感谢您的帮助。我现在将阅读路径和 Uris。我也会更新我的代码,因为现在获取文件的名称和扩展名有点不同。【参考方案2】:

您至少需要设置文件路径和正确的 mime-type。

val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension("pdf")
intent.setDataAndType(Uri.parse("file://$filePath"), mime)

【讨论】:

以上是关于使用系统对话框打开任何文件类型进行查看的主要内容,如果未能解决你的问题,请参考以下文章

MyEclipse的快捷键的使用

打开文件对话框里如何设置文件类型

为啥我的startup文件里没有任何文件

如何查看分区的文件系统

如何查看linux文件系统的类型?

记事本怎么知道用啥编码解释txt文件?