图库选图无法设置到ImageView,拍照触发FileUriExposedException闪退
解决方案
看起来你碰到了两个典型的图片选择/拍照场景问题,我来帮你逐个解决:
1. 修复图库选图后图片不显示问题
图库选图后图片无法显示,大概率是你在处理返回的Uri时没有正确解析成Bitmap,或者缺少必要的读取权限。
步骤1:确保权限配置
在AndroidManifest.xml中添加读取外部存储的权限(如果是Android 10+,可以用android:requestLegacyExternalStorage="true"兼容旧逻辑,或者改用Scoped Storage):
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 10+ 兼容配置 --> <application ... android:requestLegacyExternalStorage="true">
步骤2:正确处理图库返回的Uri
如果用AndroidX的registerForActivityResult,可以这么写:
// 初始化图库选择Launcher val pickImageLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> uri?.let { try { // 通过ContentResolver解析Uri获取Bitmap val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, it) yourImageView.setImageBitmap(bitmap) } catch (e: IOException) { e.printStackTrace() Toast.makeText(this, "图片加载失败", Toast.LENGTH_SHORT).show() } } } // 按钮点击触发图库选择 galleryBtn.setOnClickListener { pickImageLauncher.launch("image/*") }
如果是用旧的startActivityForResult,逻辑类似,在onActivityResult的RESULT_OK分支里做同样的Uri解析即可。
2. 解决拍照时的FileUriExposedException闪退问题
这个错误是Android 7.0(API 24)及以上的安全限制导致的:直接暴露file://格式的Uri给相机应用会被系统拦截,必须用FileProvider生成content://格式的安全Uri。
步骤1:配置FileProvider
在AndroidManifest.xml的<application>标签内添加FileProvider配置:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
步骤2:创建file_paths.xml文件
在res/xml目录下新建file_paths.xml(没有xml目录就自己创建),内容如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 指定拍照临时图的存储路径,这里用应用私有外部目录 --> <external-files-path name="temp_photos" path="Pictures/" /> </paths>
这个路径是应用的私有外部存储目录,Android 10+不需要额外申请WRITE权限。
步骤3:修改拍照逻辑,用FileProvider生成Uri
private var tempImagePath: String? = null // 保存临时图片路径 // 创建临时图片文件 private fun createTempImageFile(): File { val storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES) return File.createTempFile( "camera_temp_", /* 文件前缀 */ ".jpg", /* 文件后缀 */ storageDir /* 存储目录 */ ).apply { tempImagePath = absolutePath } } // 拍照Launcher val takePhotoLauncher = registerForActivityResult(ActivityResultContracts.TakePicture()) { success -> if (success && tempImagePath != null) { // 拍照成功,加载图片到ImageView val bitmap = BitmapFactory.decodeFile(tempImagePath) yourImageView.setImageBitmap(bitmap) } else { Toast.makeText(this, "拍照失败", Toast.LENGTH_SHORT).show() } } // 拍照按钮点击事件 cameraBtn.setOnClickListener { val tempFile = createTempImageFile() // 生成content://格式的Uri val photoUri = FileProvider.getUriForFile( this, "${packageName}.fileprovider", // 和Manifest里的authorities保持一致 tempFile ) takePhotoLauncher.launch(photoUri) }
额外注意点
- 如果用旧的
startActivityForResult启动相机,需要给Uri添加临时权限:
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
- Android 13+需要申请
READ_MEDIA_IMAGES权限替代READ_EXTERNAL_STORAGE,记得动态申请权限。
把这些修改完成后,你的图库选图和拍照功能应该就能正常工作了!
内容的提问来源于stack exchange,提问作者DarkShadow
相关产品推荐
相关产品推荐

