Android 13 PhotoPicker返回URI无法正常加载到ImageView的问题
Android 13 PhotoPicker URI 转字符串再解析后加载异常的解决方案
问题核心
你遇到的问题是:通过PhotoPicker获取图片URI后,直接调用setImageURI(uri)完全正常,但将URI转为字符串再用Uri.parse()解析后,仅特定固定URI能正常加载,其他URI会抛出异常。
原因分析
- 临时权限绑定问题:Android 13中PhotoPicker返回的URI携带临时访问权限,该权限是与回调中获取的原始
Uri实例关联的。当你把Uri转为字符串再重新解析,新生成的Uri对象无法继承原始实例的临时权限上下文,导致访问非公共资源时被系统拒绝。 - 特殊URI的例外情况:你测试的固定URI可能对应公共媒体库中应用已默认有权限访问的资源,因此即使重新解析也能正常加载,而其他URI对应需要临时权限验证的资源,权限丢失后就会抛出异常。
解决方案
方案1:直接使用原始Uri对象(推荐)
无需将Uri转为字符串,直接使用回调返回的原始Uri实例即可,它已经携带了正确的临时权限:
private val takeImageWithPhotoPicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> result.data?.data?.let { uri -> binding.artwork.setImageURI(uri) // 直接使用原始Uri } }
方案2:需持久化Uri时申请持久权限
如果业务需要将Uri字符串持久化存储(如保存到SharedPreferences、数据库),需先向系统申请持久化访问权限,这样后续解析字符串得到的Uri仍能正常访问资源:
private val takeImageWithPhotoPicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> result.data?.data?.let { uri -> // 申请持久化读权限 contentResolver.takePersistableUriPermission( uri, Intent.FLAG_GRANT_READ_URI_PERMISSION ) // 此时可安全转换为字符串存储 val uriString = uri.toString() // 后续解析后使用 val parsedUri = Uri.parse(uriString) binding.artwork.setImageURI(parsedUri) } }
方案3:简化PhotoPicker调用(可选)
使用AndroidX提供的PickVisualMedia契约替代StartActivityForResult,代码更简洁且更适配PhotoPicker:
private val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri -> uri?.let { binding.artwork.setImageURI(it) // 如需持久化,同样申请权限后保存字符串 contentResolver.takePersistableUriPermission( it, Intent.FLAG_GRANT_READ_URI_PERMISSION ) val savedUriStr = it.toString() } } // 调用PhotoPicker选择图片 pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
额外检查点
可以在回调中打印uri.toString()和你手动写的固定URI字符串,对比是否存在编码差异或参数遗漏(如query参数),这也可能导致解析后的Uri路径错误。
内容的提问来源于stack exchange,提问作者AdamPI
相关产品推荐
相关产品推荐

