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

调用MediaStore.ACTION_IMAGE_CAPTURE拍照后图片自动存入相册原因排查

相机拍照后自动存入相册的原因及解决办法

嘿,我来帮你捋清楚这个问题——你用MediaStore.ACTION_IMAGE_CAPTURE调用系统相机后,照片自动存进相册,其实核心原因是系统相机应用本身的默认行为,不是你的代码直接触发的~

为什么会自动存相册?

当你调用MediaStore.ACTION_IMAGE_CAPTURE但没有指定照片的输出路径时,大部分厂商的系统相机(比如原生Android、小米、华为等)都会默认把拍摄的原图保存到系统相册的默认目录里,而你通过data.getExtras().get("data")获取到的只是相机返回的缩略图,原图早就被相机应用自动存起来了,这就是相册里出现照片的原因。

怎么解决?

最靠谱的办法是指定自定义的输出路径,让相机把照片存到你指定的位置(比如应用的私有存储目录),这样就能避免相机自动把照片存进系统相册。具体步骤如下:

1. 创建私有存储目录下的临时文件

先写一个方法生成唯一的图片文件,存在应用的外部私有存储里(这样既不会污染系统相册,也不需要额外的存储权限):

private File createImageFile() throws IOException {
    // 生成唯一文件名,避免重复
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    // 获取应用外部存储的Pictures目录
    File storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    return File.createTempFile(
        imageFileName,  // 文件前缀
        ".jpg",         // 文件后缀
        storageDir      // 存储目录
    );
}

2. 修改相机调用代码,指定输出Uri

调用相机时,通过MediaStore.EXTRA_OUTPUT参数告诉相机把照片存到我们刚才创建的文件里,注意要用FileProvider来生成安全的Uri(Android 7.0+要求):

// 声明成员变量保存照片文件
private File photoFile;

// 调用相机的代码
private void takePhoto() {
    photoFile = null;
    try {
        photoFile = createImageFile();
    } catch (IOException ex) {
        // 处理文件创建失败的情况,比如弹个Toast提示用户
        Toast.makeText(requireContext(), "创建图片文件失败", Toast.LENGTH_SHORT).show();
        return;
    }
    if (photoFile != null) {
        // 生成FileProvider的Uri,替换成你的应用包名+fileprovider
        Uri photoURI = FileProvider.getUriForFile(requireContext(),
                "com.your.package.name.fileprovider",
                photoFile);
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // 指定照片输出路径
        intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
        // 授予相机临时访问Uri的权限
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        startActivityForResult(intent, CAMERA_01);
    }
}

3. 配置FileProvider(Android 7.0+必备)

AndroidManifest.xml里添加FileProvider的配置,避免Uri暴露的安全问题:

<application>
    ...
    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="com.your.package.name.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文件,指定FileProvider可以访问的路径:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 允许访问应用外部存储的Pictures目录 -->
    <external-files-path name="my_images" path="Pictures" />
</paths>

4. 修改onActivityResult处理逻辑

现在照片已经存在我们指定的文件里了,不需要再从data.getExtras()获取缩略图,直接读取文件即可:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
    super.onActivityResult(requestCode,resultCode,data);
    if(requestCode == CAMERA_01){
        if(resultCode == Activity.RESULT_OK){
            if(photoFile != null && photoFile.exists()){
                // 从指定文件读取原图Bitmap
                Bitmap bitmap = BitmapFactory.decodeFile(photoFile.getAbsolutePath());
                // 后续的Base64转换和ImageView设置
                ByteArrayOutputStream output = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);
                byte[] byte_arr = output.toByteArray();
                i11a1 = Base64.encodeToString(byte_arr, Base64.DEFAULT);
                ((SiteBefore)getActivity().getApplication()).seti11a1(i11a1);
                // 用setImageBitmap比setBackgroundDrawable更适合展示图片
                img11a1.setImageBitmap(bitmap);
            }
        }else if(resultCode == Activity.RESULT_CANCELED){
            // 处理用户取消拍照的情况
        }
    }
}

额外说明

有些同学可能会问:有没有办法不指定路径,直接让相机不存相册?其实这个兼容性很差,不同厂商的相机应用对额外Intent参数的支持不一样,所以还是指定自定义路径的方法最稳妥,既能控制照片的存储位置,又能避免自动存入系统相册。

内容的提问来源于stack exchange,提问作者BrenDonie

火山引擎 最新活动