Android相机拍照显示至ImageView崩溃求助(图库功能正常)
解决相机拍照崩溃的问题
看起来你的图库选择功能正常,但相机拍照时崩溃,大概率是Android版本适配和权限这两个核心问题导致的,我帮你一步步排查修复:
一、先处理最常见的FileUriExposedException(Android 7.0+)
在Android N及以上系统,直接用Uri.fromFile(file)传递文件Uri会触发FileUriExposedException——系统禁止跨应用暴露file://类型的Uri,必须用FileProvider生成content://类型的Uri来替代。
修复步骤:
- 在
AndroidManifest.xml中注册FileProvider
<application> ... <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> </application>
(如果你用的是support库,把androidx.core.content.FileProvider换成android.support.v4.content.FileProvider)
- 创建
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-path name="my_images" path="." /> </paths>
这个配置允许FileProvider访问外部存储的根目录。
- 修改相机Intent的Uri生成逻辑
把原来的uri= Uri.fromFile(file);替换成版本适配的代码,同时添加临时权限:
File file=new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // Android 7.0及以上用FileProvider生成Uri uri = FileProvider.getUriForFile(NewAdActivity.this, getPackageName() + ".fileprovider", file); // 给相机添加临时读写权限 camera_intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); camera_intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } else { // 低版本直接用Uri.fromFile uri = Uri.fromFile(file); }
二、检查权限是否齐全
Android 6.0(API 23)及以上,相机权限和存储权限需要动态申请,不能只在Manifest里声明。
1. 在AndroidManifest.xml中声明权限
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Android 10+ 可以用更精细的媒体权限替代 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:maxSdkVersion="33" /> <uses-feature android:name="android.hardware.camera" android:required="false" />
2. 动态申请权限再启动相机
把启动相机的逻辑封装成方法,先检查权限再调用:
// 点击拍照选项时先检查权限 else if (i == 1){//相机 String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}; if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { // 申请权限 ActivityCompat.requestPermissions(this, permissions, 100); } else { // 权限已授予,启动相机 launchCamera(); } } // 封装的启动相机方法 private void launchCamera() { Intent camera_intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File file=new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { uri = FileProvider.getUriForFile(NewAdActivity.this, getPackageName() + ".fileprovider", file); camera_intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); camera_intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } else { uri = Uri.fromFile(file); } camera_intent.putExtra(MediaStore.EXTRA_OUTPUT,uri); // 移除冲突的return-data参数 // camera_intent.putExtra("return-data",true); startActivityForResult(camera_intent,1); }
3. 处理权限申请结果
重写onRequestPermissionsResult方法:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 100) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } if (allGranted) { launchCamera(); } else { Toast.makeText(this, "需要相机和存储权限才能拍照", Toast.LENGTH_SHORT).show(); } } }
三、移除冲突的return-data参数
当你设置了MediaStore.EXTRA_OUTPUT指定图片保存路径后,return-data设为true是无效的,还可能导致相机返回数据异常,直接删掉这行代码即可。拍照完成后,直接通过你保存的uri加载图片到ImageView:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (requestCode == 1) { // 拍照成功,用uri加载图片 images.get(current_image).setImageURI(uri); fill_images[current_image] = true; } else if (requestCode == 2) { // 图库选择逻辑保持不变 Uri selectedUri = data.getData(); images.get(current_image).setImageURI(selectedUri); fill_images[current_image] = true; } } }
额外注意点
- 创建文件前可以先检查外部存储是否可用:
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)),如果存储未挂载,提示用户。 - 你原来的文件名生成代码
String.valueOf(System.currentTimeMillis()+".jpg")可以简化为System.currentTimeMillis() + ".jpg",long类型和字符串拼接会自动转成字符串。
把这些修改都应用后,相机拍照的崩溃问题应该就能解决了。
内容的提问来源于stack exchange,提问作者hassan abbasi
相关产品推荐
相关产品推荐

