You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Marshmallow相机拍照功能异常,其余版本正常技术求助

解决Android Marshmallow下相机拍照不显示在图库的问题

嘿,我看你遇到了个挺头疼的问题——相机拍照逻辑在除Android 6.0(Marshmallow,API 23)之外的设备都正常,唯独这个版本出问题,而且你已经排查过常规环节了。结合你给的代码片段,我大概率能定位到几个Marshmallow特有的坑,咱一步步来捋:

1. 权限判断的逻辑漏洞

Marshmallow是Android第一个引入运行时权限的版本,你的代码里有个关键判断:if (Build.VERSION.SDK_INT > M)——这里的M就是API23,也就是说Marshmallow本身会走到else分支,但这个版本恰恰需要严格的运行时权限检查!

如果你的PermissionManager.userHasPermission方法没有专门适配API23的权限校验逻辑,那很可能在Marshmallow上,你以为权限已经授予了,但实际上用户并没有在运行时同意,直接调用相机就会静默失败。

2. 媒体库刷新的兼容性问题

就算拍照成功保存了文件,Marshmallow对媒体库的更新机制和之前版本不一样——如果你只是把图片写到文件夹里,不主动通知媒体库扫描,图库的“最近”文件夹根本不会显示这张新图。这是很多开发者容易忽略的点!

3. 代码分支的逻辑错误

你代码里把API>23的情况导向了GetImageFromGallery(),但API23本身走else分支——如果else分支里的拍照逻辑没有适配Marshmallow的权限和文件规则,比如直接用File Uri而不是FileProvider,就会触发FileUriExposedException,导致拍照失败。


具体修复建议

先把权限逻辑掰正

首先要把权限判断和申请的逻辑统一适配所有版本,尤其是Marshmallow:

public void getImage() {
    final PermissionManager permissionManager = new PermissionManager();
    if (permissionManager.userHasPermission(Addfood_items.this.getContext())) {
        // 权限没问题,直接走拍照逻辑
        takePhoto();
    } else {
        // 主动申请相机+存储权限(Marshmallow及以上必须这么做)
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                1001); // 自定义请求码
    }
}

// 别忘了处理权限申请的回调
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 1001) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            takePhoto();
        } else {
            Toast.makeText(this, "需要相机权限才能拍照哦", Toast.LENGTH_SHORT).show();
        }
    }
}

拍照后一定要通知媒体库

保存图片之后,必须调用MediaScannerConnection来刷新媒体库,这样图库才能及时看到新图片:

// 假设你已经把图片保存到了imageFile这个文件里
MediaScannerConnection.scanFile(getContext(),
        new String[]{imageFile.getAbsolutePath()},
        new String[]{"image/jpeg"},
        (path, uri) -> {
            // 扫描完成,这里可以做后续操作,比如更新UI
        });

用FileProvider避免Uri暴露问题

Marshmallow及以上版本不允许直接暴露File类型的Uri给其他应用(比如相机),必须用FileProvider来生成安全的Uri:

// 先创建保存图片的临时文件
private File createImageFile() throws IOException {
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    return File.createTempFile(
            imageFileName,  /* 前缀 */
            ".jpg",         /* 后缀 */
            storageDir      /* 存储目录 */
    );
}

// 启动相机的逻辑
private void takePhoto() {
    try {
        File imageFile = createImageFile();
        Uri imageUri = FileProvider.getUriForFile(this,
                "com.your.app.package.fileprovider", // 要和你Manifest里的一致
                imageFile);
        Intent takePicIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        takePicIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        // 给相机临时的写入权限
        takePicIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        startActivityForResult(takePicIntent, 1002);
    } catch (IOException e) {
        e.printStackTrace();
        Toast.makeText(this, "创建图片文件失败", Toast.LENGTH_SHORT).show();
    }
}

最后建议你在Marshmallow设备上打开Logcat,看看有没有权限拒绝、文件写入失败或者Uri暴露的异常日志,这些日志能帮你快速锁定具体问题!

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:46:46