Android13照片选择器选图后OkHttp发送报EFAULT(Bad address)错误
问题描述
- 仅在Android 13系统使用Photo Picker选择图片时出现错误,无Photo Picker的版本运行正常。
- 代码逻辑:用户通过Photo Picker选图后获取图片Uri,调用
getFileFromUri方法转换为File对象的步骤正常;但使用Retrofit将该File作为multipart请求体发送时,LogCat出现警告/sdcard/.transforms/synthetic/picker/...: open failed: EFAULT (Bad address),随后Retrofit/OkHttp抛出异常。 - 当前配置:Retrofit版本为
com.squareup.retrofit2:retrofit:2.9.0;AndroidManifest中已配置WRITE_EXTERNAL_STORAGE、READ_EXTERNAL_STORAGE、READ_MEDIA_IMAGES权限,application节点设置android:requestLegacyExternalStorage="true";权限申请逻辑为Android 13及以上请求READ_MEDIA_IMAGES,其他版本请求READ_EXTERNAL_STORAGE。 - 疑问:能否不使用
MANAGE_EXTERNAL_STORAGE权限解决该问题?是否需要将图片复制到应用内部存储目录?
解决方案
- 不需要申请
MANAGE_EXTERNAL_STORAGE权限,该权限属于系统严格管控的特殊权限,你的场景完全可以通过常规方式解决。 - 必须将图片复制到应用内部存储目录。Android 13的Photo Picker返回的是虚拟Uri,对应的文件路径是系统生成的临时合成路径,应用没有直接读取该文件的完整权限,即便成功转换为File对象,实际访问时仍会触发权限异常。
- 具体操作步骤:
- 拿到Photo Picker返回的Uri后,通过
ContentResolver读取文件输入流。 - 将输入流复制到应用内部存储目录(比如
getCacheDir()或getFilesDir()下的子目录),生成新的File对象。 - 使用内部存储的File对象作为Retrofit的multipart请求体,即可正常完成文件上传。
- 拿到Photo Picker返回的Uri后,通过
- 额外注意:上传完成后,记得在合适的时机清理内部存储中的临时图片文件,避免占用过多设备存储空间。
内容的提问来源于stack exchange,提问作者Yoko999
相关产品推荐
相关产品推荐

