安卓系统中的多种 MIME 类型

90

有没有一种方法可以使用 intent.setType() 并同时提供多个广泛的类型(比如图片和视频)?

我正在使用一个 ACTION_GET_CONTENT。它似乎只能使用逗号分隔的类型。


1
你能具体一点吗?在什么上调用setType()方法?用于什么目的和用途?等等。 - CommonsWare
你找到解决这个问题的方法了吗? - Rohith Nandakumar
7个回答

142

在使用存储访问框架时,Android 4.4可以使用EXTRA_MIME_TYPES传递多个MIME类型。

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
String[] mimetypes = {"image/*", "video/*"};
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes);
startActivityForResult(intent, REQUEST_CODE_OPEN);

7
这在Android 7.0上无效,只显示视频。 - clocksmith
@clocksmith 在我的Nexus 9上,运行良好,使用的是Android 7.0。 - Steve M
@clocksmith 在 Android 7.0 模拟器上也可以正常工作。有什么特定的情况不起作用吗?因为它是官方 API 的一部分,所以似乎这是正确的答案。 - Steve M
完美工作。Android 过滤文件类型的方式。 - Nikhil
3
请注意,EXTRA_MIME_TYPES不能替代setType。使用这个方法时,你仍然需要使用setType函数。 - arlomedia
显示剩余3条评论

25

实际上,支持多个MIME类型。你试过吗?

例如:intent.setType("image/*,video/*") 将显示照片和视频...

对我来说有效。对你也应该有效...

[编辑]: 这部分有效,但并非所有图库应用程序都选择实现对多个MIME类型筛选的支持。


5
这个解决方案在可允许两种 MIME 类型的应用程序中有效,但默认应用“相册”不支持。 - Corbella
1
实际上,这取决于您安装的“相册”应用程序。不同版本的应用程序会随不同的Android ROM进行分发。 - bazyle
仅适用于我的一些小问题。相同的图像可能可选,也可能不可选。Android 5.0.1 - Ingweland

4

抱歉,目前不支持此功能。您有两个选项:

(1) 使用 MIME 类型 */*,接受用户可能会选择一些您无法处理的内容(并为此提供合适的恢复路径);或者

(2) 实现自己的活动选择器,在包管理器上进行直接调用,获取可以处理意图的 MIME 类型的活动的列表,将这些列表合并,并将其显示给用户。

另外,setType() 不支持逗号分隔的类型。它必须是一个且仅有一个 MIME 类型。


3
实际上,支持多种 MIME 类型。你有尝试过吗?例如:image/、video/ 将显示照片和视频... - bazyle
@vchelbanster 不是所有设备都支持多个MIME类型。在某些Android版本(如<5.0)中,它只会选择第一个MIME类型。 - Shivam Pokhriyal
@ShivamPokhriyal 部分同意 - 它并不适用于所有应用程序。由于获取组合意图类型的应用程序需要处理多个MIME类型才能使其正常工作,因此并非所有应用程序(如画廊应用程序)都能正常工作,这可能会给人留下它是依赖于操作系统版本的印象。实际上,是应用程序的创建者需要处理多个MIME类型。所以,是的 - 它的支持有限。请参见我的答案。 - bazyle
@vchelbanster 是的,一开始我也觉得这与操作系统版本有关。后来我发现,如果您的设备没有处理此类意图的应用程序,则会出现问题。 - Shivam Pokhriyal

2

对我而言,最有效的方法是:

intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);

您可以像这样添加多个MIME类型

intent.setType("image/*|application/pdf|audio/*");

但是,意图选择器只会显示可以处理图像的应用程序,因为它是mime类型字符串中的第一个。

然而,如果您安装了文件管理器(我使用CyanogenMod文件管理器进行测试),则可以选择音频、pdf或图像文件。

如果音频mime类型是第一个,就像这样:

intent.setType("audio/*|image/*|application/pdf");

意图选择器将只显示处理音频的应用程序。
同样,使用文件管理器,您可以选择图像、PDF或音频。


1
你可以通过使用 | 分隔来传递多个 MIME 类型
Intent.setType("application/*|text/*");

0
使用registerForActivityResult()回调函数:
import androidx.activity.result.contract.ActivityResultContracts


class DocumentsFragment : Fragment() {

    companion object {

        // 1. List of MIME types
        /**@see <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types">MIME types</a>
         * @see <a href="https://www.iana.org/assignments/media-types/media-types.xhtml">IANA - MIME types</a>*/
        private val MIME_TYPES: Array<String> = arrayOf(
            "image/*", "application/pdf", "application/msword",
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "application/vnd.oasis.opendocument.text", "text/plain", "text/markdown"
        )
    }
    
    //2. Register for Activity Result callback as class field
    private val getDocuments =
    registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()/*NOT OpenDocument*/) {
        Log.d("Open documents", "incoming uri: size = ${it.size}")
        add(it)
    }
    
    ...
    //3. set onclick listener
    selectDocumentsButton.setOnClickListener { getDocuments.launch(MIME_TYPES) }
    ...
    
    //4. handle incoming uri list
    private fun add(list: List<Uri>) {
        val setOfFiles = copyToAppDir(list)
        setOfFiles.forEach {
            //TODO: do something            
        }
    }
    
    //5. copy the files to the application folder for further work
    private fun copyToAppDir(list: List<Uri>): Set<File> {
        val set = mutableSetOf<File>()
        list.forEach { uri ->
            try {
                val file: File = copyUriContentToTempFile(uri)
                set.add(file)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        return set
    }
    
    //6. copy selected content by uri
    private fun copyUriContentToTempFile(uri: Uri): File {
        val inputStream = requireContext().contentResolver.openInputStream(uri)
        inputStream.use { input ->
            val tempFile: File = .. ; //TODO: create file
            tempFile.outputStream().use { output ->
                input?.copyTo(output)
            }
            return tempFile
        }
    }
}


-3

关于我的分号工作。

示例:

intent.setType("image/*;video/*")

或者

sIntent.putExtra("CONTENT_TYPE", "image/*;video/*"); 

1
你可以使用Intent.EXTRA_MIME_TYPES常量代替硬编码的"CONTENT_TYPE"字符串。此外,你可以传递一个字符串数组来代替分号。 - Fred

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接