将多种 Mime 类型传递给 ActivityResultLauncher.launch()

问题描述 投票:0回答:3

我有以下代码

val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
    //Some code here..
}

还有其他地方,

getContent.launch("application/vnd.openxmlformats-officedocument.wordprocessingml.document")

我可以成功选择docx文件。我需要选择 pdf 或 doc 或文本或 docx 而只是能够选择一种(此处为 docx)。

kotlin mime-types onactivityresult registerforactivityresult
3个回答
20
投票

我建议使用

OpenDocument
而不是
GetContent

val documentPick =
    registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
        // do something 
    }

启动意图时只需添加您想要获取的 mime 类型

documentPick.launch(
            arrayOf(
                "application/pdf",
                "application/msword",
                "application/ms-doc",
                "application/doc",
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                "text/plain"
            )
        )

5
投票

使用数组在我的情况下不起作用。相反,以下工作正常。 这里使用了 ActivityResultContracts.GetContent 的自定义类。 fun“createIntent”被重写以自定义方法以从输入中获取意图。

    // custom class of GetContent: input string has multiple mime types divided by ";"
    // Here multiple mime type are divided and stored in array to pass to putExtra.
    // super.createIntent creates ordinary intent, then add the extra. 
    class GetContentWithMultiFilter:ActivityResultContracts.GetContent() {
        override fun createIntent(context:Context, input:String):Intent {
            val inputArray = input.split(";").toTypedArray()
            val myIntent = super.createIntent(context, "*/*")
            myIntent.putExtra(Intent.EXTRA_MIME_TYPES, inputArray)
            return myIntent
        }
    }

    // define ActivityResultLauncher to launch : using custom GetContent
    val getContent=registerForActivityResult(GetContentWithMultiFilter()){uri ->
    ... // do something
    }

    // launch it
    // multiple mime types are separated by ";".
    val inputString="audio/mpeg;audio/x-wav;audio/wav"
    getContent.launch(inputString)

0
投票

GetContent
合约仅采用单个
String
参数,该参数只能包含单个MIME类型。

OpenDocument
合约采用一组
String
,每个数组都有一个 MIME 类型。

各有利弊,因此请参阅此 StackOverflow 问题以帮助您决定使用哪一个。我不知道为什么决定将

GetContact
限制为单一 MIME 类型。

lglink 的答案展示了一种获得多 MIME

GetContent
的方法,即通过使用
;
分隔的串联 MIME 类型的
String
来扩展该契约。

我用另一种方式解决了这个问题,按照官方文档制作自定义合同

class BespokeContract: ActivityResultContract<Array<String>, Uri?>() {
    @CallSuper
    override fun createIntent(context: Context, input: Array<String>): Intent {
        return Intent(Intent.ACTION_GET_CONTENT)
            .addCategory(Intent.CATEGORY_OPENABLE)
            .setType("*/*")
            .putExtra(Intent.EXTRA_MIME_TYPES, input)
    }

    override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
        return intent.takeIf { resultCode == Activity.RESULT_OK }?.data
    }
}

作为一名 Android 编程新手,我花了很多功夫才得到这个。这些文档没有提到一些事情,否则我的代码就无法工作。也许它们是经验丰富的 Android 开发人员的常识,但对于 2023 年涉足该领域的人来说,情况并非如此。我最终不得不查看 Android 源代码

GetContent
:

  1. GetContent
    合约使用
    ACTION_GET_CONTENT
    意图:
        Intent(Intent.ACTION_GET_CONTENT)
    
  2. 如果您要签订新合同而不是延长现有合同,则需要添加
    OPENABLE
    类别。如果你不这样做,你会得到一个令人困惑的错误:
            .addCategory(Intent.CATEGORY_OPENABLE)
    
  3. 在放置额外的 mime 类型之前,您必须首先使用
    setType()
    ,即使您放置在那里的内容将被忽略。
    */*
    很常见,而且可能是最短的。如果你不这样做,你会再次得到一个令人困惑的错误:
            .setType("*/*")
    
  4. 当然还有主要部分:
            .putExtra(Intent.EXTRA_MIME_TYPES, input)
    

对于像我一样在互联网上搜索帮助时看到多种方法而感到困惑的人,不知道哪些方法已被弃用,哪些是由于旧的 Views 代码与新的 Compose 代码等造成的,这是一种等效的不同编码方式

 createIntent

override fun createIntent(context: Context, input: Array<String>) =
    Intent(Intent.ACTION_GET_CONTENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "*/*"
        putExtra(Intent.EXTRA_MIME_TYPES, input)
    }
© www.soinside.com 2019 - 2024. All rights reserved.