You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android相机拍摄图片无法在CircleImageView显示问题求助

相机拍照图片无法显示在CircleImageView的解决方案

看起来你遇到的问题主要是几个逻辑和适配问题导致的,我帮你拆解并给出修复方案:

核心问题分析

  1. RequestCode判断错误:你调用相机拍照时用的是REQUEST_IMAGE_CAPTURE作为请求码,但在onActivityResult里却判断的是MY_CAMERA_REQUEST_CODE——后者是申请相机权限的请求码,这直接导致相机拍照完成后的逻辑根本没执行。
  2. Android 7.0+ Uri适配问题:从API 24开始,直接使用file://格式的Uri会触发FileUriExposedException,导致相机无法正常保存照片,自然无法读取显示。
  3. 权限申请后逻辑缺失:用户第一次授予相机权限后,你没有再次调用拍照方法,导致权限申请完成后不会触发拍照动作。

修复步骤和代码

第一步:配置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

火山引擎 最新活动