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

Android API30-31选图时调用File.exists()触发空指针异常问题

问题根因

崩溃触发点非常明确:AddImage.java第149行调用file.exists()时,getOutputMediaFile(1)返回了null对象,触发空指针异常。
API29环境正常、API30+崩溃的核心原因是Android分区存储机制变更:

  • API29时应用还可以通过在Manifest中添加android:requestLegacyExternalStorage="true"绕过分区存储限制,直接读写外部存储公共路径
  • API30及以上版本强制启用分区存储,即使你申请了WRITE_EXTERNAL_STORAGE权限,也无法直接访问外部存储公共根目录、Environment.getExternalStoragePublicDirectory()这类非应用专属路径。你的getOutputMediaFile方法大概率是在这类无权限的路径下创建文件,创建失败直接返回null,最终触发崩溃。

另外你的代码还存在两处逻辑冗余问题:

  • 相册选择场景下完全不需要提前创建临时文件,ACTION_GET_CONTENT/ACTION_PICK会直接返回系统相册的图片Uri,提前创建文件属于无效操作
  • 相册选择逻辑中判断相机权限、写入存储权限属于多余判断,API30+通过系统选择器选图不需要申请任何存储权限,更不需要相机权限。
修复步骤
  1. 所有调用getOutputMediaFile()的位置先做非空判断,拿到非null的File对象后再执行后续文件操作,从根源避免空指针
  2. 修改getOutputMediaFile的文件存储路径,改用应用专属外部存储目录,这类目录不需要申请任何存储权限即可在所有Android版本正常读写,参考实现:
private File getOutputMediaFile(int type) {
    // 替换原有公共存储路径为应用专属图片目录
    File mediaStorageDir = new File(requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES), "PetImages");
    if (!mediaStorageDir.exists()) {
        // 目录创建失败直接返回null,上层做好空判断
        if (!mediaStorageDir.mkdirs()) return null;
    }
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    if (type == 1) {
        return new File(mediaStorageDir, "IMG_" + timeStamp + ".jpg");
    }
    return null;
}
  1. 精简相册选择逻辑,删除多余的临时文件创建、无关权限判断代码,参考实现:
case R.id.gallery_cards:
    Intent pickIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    pickIntent.setType("image/*");
    startActivityForResult(Intent.createChooser(pickIntent, "Select Picture"), PICK_FROM_GALLERY);
    break;
  1. 若后续需要兼容API33及以上版本,注意废弃旧的READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE权限,读取相册图片按需申请READ_MEDIA_IMAGES权限即可,使用系统照片选择器时无需申请该权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 13:27:33