Android Kotlin使用FileProvider调用相机后ImageView黑屏无响应问题
问题解决:Fragment中调用相机后显示图片黑屏无响应
核心问题分析
你当前的代码存在两个致命问题:
- 启动相机后立即解码图片,此时相机还未完成拍摄,
photoFile中没有有效图像数据,甚至可能为空。 - 直接解码原图会导致内存溢出,引发界面黑屏无响应。
分步解决方案
1. 修正相机调用逻辑,在拍摄完成后再加载图片
必须在相机返回成功结果的回调中处理图片加载,不能提前执行解码操作。
2. 对图片进行采样压缩,避免内存不足
相机拍摄的原图分辨率极高,直接加载会占用大量内存,必须按ImageView的尺寸压缩后再显示。
3. 确保FileProvider配置正确
如果FileProvider的权限或路径配置错误,相机无法写入图片文件,也会导致后续加载失败。
完整修正代码
第一步:定义全局变量与相机启动代码
private var photoFile: File? = null private const val FILE_NAME = "temp_photo" private const val REQUEST_CODE_CAMERA = 3 // 启动相机的方法 private fun startCamera() { val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) // 获取应用私有图片目录 activity?.getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.let { storageDir -> try { // 创建临时图片文件 photoFile = File.createTempFile(FILE_NAME, ".jpg", storageDir) photoFile?.let { file -> // 获取FileProvider的Uri val fileProviderUri = FileProvider.getUriForFile( requireContext(), "com.example.an0nym0us.fileprovider", // 需与AndroidManifest中配置一致 file ) takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileProviderUri) startActivityForResult(takePictureIntent, REQUEST_CODE_CAMERA) } } catch (e: IOException) { e.printStackTrace() // 处理文件创建失败的情况 } } }
第二步:重写onActivityResult处理返回结果
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) // 确认相机拍摄成功 if (requestCode == REQUEST_CODE_CAMERA && resultCode == Activity.RESULT_OK) { photoFile?.let { file -> // 按ImageView尺寸压缩加载图片 val targetWidth = yourImageView.width val targetHeight = yourImageView.height val bitmap = decodeSampledBitmapFromFile(file.absolutePath, targetWidth, targetHeight) yourImageView.setImageBitmap(bitmap) } } }
第三步:添加图片压缩工具方法
// 采样压缩解码图片 private fun decodeSampledBitmapFromFile(path: String, reqWidth: Int, reqHeight: Int): Bitmap { val options = BitmapFactory.Options() // 先获取图片原始尺寸,不加载到内存 options.inJustDecodeBounds = true BitmapFactory.decodeFile(path, options) // 计算合适的采样率 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight) // 解码图片到内存 options.inJustDecodeBounds = false return BitmapFactory.decodeFile(path, options) } // 计算采样率,确保压缩后图片尺寸不超过目标尺寸 private fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int { val height = options.outHeight val width = options.outWidth var inSampleSize = 1 if (height > reqHeight || width > reqWidth) { val halfHeight = height / 2 val halfWidth = width / 2 while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) { inSampleSize *= 2 } } return inSampleSize }
第四步:检查FileProvider配置
在AndroidManifest.xml中添加FileProvider声明:
<application> ... <provider android:name="androidx.core.content.FileProvider" android:authorities="com.example.an0nym0us.fileprovider" <!-- 与代码中一致 --> android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> ... </application>
在res/xml目录下创建file_paths.xml文件(若没有xml目录需手动创建):
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 对应getExternalFilesDir(Environment.DIRECTORY_PICTURES)的路径 --> <external-files-path name="my_pictures" path="Pictures" /> </paths>
第五步:权限检查
Android 6.0及以上系统需动态申请相机权限:
// 检查并申请相机权限 private fun checkCameraPermission() { if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions( requireActivity(), arrayOf(Manifest.permission.CAMERA), 100 ) } else { startCamera() } } // 处理权限申请结果 override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == 100 && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { startCamera() } else { // 处理权限被拒绝的情况 } }
关键注意事项
- 必须等待相机返回
RESULT_OK后再加载图片,否则文件内容无效。 - 永远不要直接加载原图,采样压缩是避免内存溢出的必要操作。
- FileProvider的
authorities必须和代码、配置文件完全一致,否则相机无法写入文件。
内容的提问来源于stack exchange,提问作者Joshua Perez
相关产品推荐
相关产品推荐

