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+通过系统选择器选图不需要申请任何存储权限,更不需要相机权限。
修复步骤
- 所有调用
getOutputMediaFile()的位置先做非空判断,拿到非null的File对象后再执行后续文件操作,从根源避免空指针 - 修改
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; }
- 精简相册选择逻辑,删除多余的临时文件创建、无关权限判断代码,参考实现:
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;
- 若后续需要兼容API33及以上版本,注意废弃旧的
READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE权限,读取相册图片按需申请READ_MEDIA_IMAGES权限即可,使用系统照片选择器时无需申请该权限。
内容的提问来源于stack exchange,提问作者nexti
相关产品推荐
相关产品推荐

