Android相机拍摄图片无法在CircleImageView显示问题求助
相机拍照图片无法显示在CircleImageView的解决方案
看起来你遇到的问题主要是几个逻辑和适配问题导致的,我帮你拆解并给出修复方案:
核心问题分析
- RequestCode判断错误:你调用相机拍照时用的是
REQUEST_IMAGE_CAPTURE作为请求码,但在onActivityResult里却判断的是MY_CAMERA_REQUEST_CODE——后者是申请相机权限的请求码,这直接导致相机拍照完成后的逻辑根本没执行。 - Android 7.0+ Uri适配问题:从API 24开始,直接使用
file://格式的Uri会触发FileUriExposedException,导致相机无法正常保存照片,自然无法读取显示。 - 权限申请后逻辑缺失:用户第一次授予相机权限后,你没有再次调用拍照方法,导致权限申请完成后不会触发拍照动作。
修复步骤和代码
第一步:配置FileProvider(解决Uri暴露问题)
在AndroidManifest.xml中添加FileProvider配置,用于生成安全的文件Uri:
<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>
然后在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="camera_photos" path="Pictures" /> </paths>
这个配置指定照片会保存在APP专属的外部存储Pictures目录,避免权限冲突。
第二步:修正拍照方法和权限处理
private static final int GALLERY = 1; private static final int REQUEST_IMAGE_CAPTURE = 2; private static final int MY_CAMERA_REQUEST_CODE = 3; private Uri fileUri; private CircleImageView image; // 确保你已经在onCreate中初始化了这个View @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_activity_layout); image = findViewById(R.id.photo); // 其他初始化代码... } @RequiresApi(api = Build.VERSION_CODES.M) private void takePhotoFromCamera() { if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.CAMERA}, MY_CAMERA_REQUEST_CODE); return; // 先申请权限,等回调后再执行拍照 } // 创建保存照片的临时文件 File photoFile = createImageFile(); if (photoFile != null) { // 用FileProvider生成安全Uri fileUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile); Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // 给相机授予临时读取权限 takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); } } } // 创建保存图片的临时文件 private File createImageFile() { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String imageFileName = "PROFILE_PHOTO_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); try { return File.createTempFile(imageFileName, ".jpg", storageDir); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "创建照片文件失败", Toast.LENGTH_SHORT).show(); return null; } } // 权限申请回调 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == MY_CAMERA_REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 用户同意权限,重新调用拍照方法 takePhotoFromCamera(); } else { Toast.makeText(this, "需要相机权限才能拍照", Toast.LENGTH_SHORT).show(); } } }
第三步:修正onActivityResult逻辑
@RequiresApi(api = Build.VERSION_CODES.KITKAT) @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_CANCELED) { return; } if (requestCode == GALLERY) { if (data != null) { Uri contentURI = data.getData(); try { Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), contentURI); image.setImageBitmap(bitmap); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "图库图片加载失败", Toast.LENGTH_SHORT).show(); } } } else if (requestCode == REQUEST_IMAGE_CAPTURE) { // 相机拍照完成,读取照片并显示 try { ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(fileUri, "r"); if (parcelFileDescriptor != null) { FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); // 压缩图片避免OOM BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 4; // 根据实际需求调整压缩比例 Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options); // 适配CircleImageView的尺寸 Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, image.getWidth(), image.getHeight(), true); image.setImageBitmap(scaledBitmap); bitmap.recycle(); // 回收原Bitmap节省内存 parcelFileDescriptor.close(); } } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "相机照片加载失败", Toast.LENGTH_SHORT).show(); } } }
修复说明
- 修正了
onActivityResult中的请求码判断,相机拍照回调对应REQUEST_IMAGE_CAPTURE - 使用
FileProvider生成安全Uri,解决Android 7.0+的Uri暴露异常 - 完善了权限申请后的逻辑,用户授权后自动触发拍照
- 添加了图片压缩和尺寸适配,避免内存溢出问题
- 用
ContentResolver读取图片,比直接解析文件路径更可靠
内容的提问来源于stack exchange,提问作者Tommaso




