使用ACTION_CREATE_DOCUMENT的Intent能否附加extra,为何onActivityResult取值为null
问题原因
你附加到ACTION_CREATE_DOCUMENT Intent上的自定义Extra不会被返回,核心原因是:
这个Intent启动的是系统内置的文件选择器组件,系统组件在处理完创建文件的逻辑后,只会返回规范定义的返回数据(比如创建成功的文件Uri),不会把你传入的自定义Extra原封不动带回给你的App,所以你在onActivityResult的返回Intent里读不到url参数,自然返回null。
解决方案
- 方案1:直接存为类成员变量
如果你的url是单次请求场景,不存在多请求并发的情况,可以直接把要传递的url存为当前Activity/Fragment的成员变量,回调时直接读取即可。
示例代码:
// 类内定义成员变量 private var currentRequestUrl: String? = null private fun createFile(pickerInitialUri: Uri, url: String) { currentRequestUrl = url // 赋值给成员变量 val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "application/pdf" putExtra(Intent.EXTRA_TITLE, "invoice.pdf") putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri) } startActivityForResult(intent, CREATE_FILE) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == CREATE_FILE && resultCode == Activity.RESULT_OK) { // 直接读取成员变量即可 val url = currentRequestUrl // 后续逻辑处理 currentRequestUrl = null // 用完清空避免内存泄漏 } }
- 方案2:用请求码做映射适配多请求场景
如果存在多个不同url的创建请求同时发起的场景,可以维护一个请求码和对应参数的映射表,用唯一请求码区分不同请求:
private val requestParamMap = mutableMapOf<Int, String>() private var requestCodeGenerator = 2 // 避开已经定义的固定请求码 private fun createFile(pickerInitialUri: Uri, url: String) { val requestCode = requestCodeGenerator++ requestParamMap[requestCode] = url val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "application/pdf" putExtra(Intent.EXTRA_TITLE, "invoice.pdf") putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri) } startActivityForResult(intent, requestCode) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (resultCode == Activity.RESULT_OK) { val url = requestParamMap.remove(requestCode) // 拿到url后处理后续逻辑 } }
- 方案3:使用Activity Result API(推荐,适配新版Android规范)
如果是新项目或者已经适配了Jetpack组件,使用Activity Result API可以直接通过闭包捕获参数,无需额外存储:
// 注册创建文件的结果回调 private val createFileLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("application/pdf")) { uri -> uri ?: return@registerForActivityResult // 这里可以直接访问调用时传入的url参数,通过闭包捕获 // 后续处理逻辑 } // 调用创建文件的方法 private fun createFile(pickerInitialUri: Uri, url: String) { createFileLauncher.launch("invoice.pdf", ActivityOptions.makeBasic().apply { putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri) }.toBundle()) }
注意事项
所有启动系统内置组件的Intent(比如ACTION_OPEN_DOCUMENT、ACTION_PICK、ACTION_GET_CONTENT等),自定义的Extra都不会被系统组件回传,不要依赖这种方式传递参数。
内容的提问来源于stack exchange,提问作者Lukas
相关产品推荐
相关产品推荐

