Android 9/10部分设备拍照时getExternalFilesDir返回空路径问题咨询
问题描述
现有相机拍照的实现逻辑在多数设备上运行正常,但在部分Android 9、Android 10设备上,会出现pictureFilePath为空、最终导致var_Bitmap取值为null的问题。需要确认两个问题:
getExternalFilesDir(Environment.DIRECTORY_PICTURES)是否在所有设备上都能正常生效?- 是否存在其他诱因导致该问题?
现有代码
相机启动逻辑
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File imagefile = null; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); try { imagefile = File.createTempFile("pic", ".jpg", storageDir); } catch (IOException e) { e.printStackTrace(); } pictureFilePath = imagefile.getAbsolutePath(); Uri photoURI = FileProvider.getUriForFile(this, "com.xyz.xyz.fileprovider", imagefile); cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(cameraIntent, 2);
拍照回调onActivityResult逻辑
File imgFile = new File(pictureFilePath); if (imgFile.exists()) { var_imageview_browse.setImageURI(Uri.fromFile(imgFile)); var_imageview_browse.setScaleType(ImageView.ScaleType.FIT_XY); var_Bitmap = BitmapFactory.decodeFile(pictureFilePath); imgFile.delete(); if (var_Bitmap == null) { var_textview_er.setText("An error occurred."); } else { var_Bitmap = Bitmap.createScaledBitmap(var_Bitmap, INPUT_SIZE, INPUT_SIZE, false); } }
问题解答
关于getExternalFilesDir的兼容性
该方法从Android 2.2(API 8)开始就作为系统公开API存在,本身没有跨版本的兼容问题,但存在两种异常返回null的场景:
- 设备的外部存储处于未挂载、物理损坏状态时,该方法会直接返回null。
- 部分定制ROM修改了存储分区的挂载逻辑,极端情况下会出现该目录初始化失败、返回null的情况。
但这不是导致问题的核心诱因,现有代码本身存在多个明显漏洞,才是触发异常的主要原因:
- 空指针完全未做校验
代码既没有判断storageDir是否为null,也没有校验imagefile的创建结果:- 如果
storageDir返回null,或者File.createTempFile抛出IO异常,imagefile就会保持初始的null状态,下一行直接调用imagefile.getAbsolutePath()会直接抛出空指针异常,导致pictureFilePath根本没有被正常赋值,最终为空值。 - 你遇到的
pictureFilePath为空的问题,大概率就是这个场景:部分Android 9/10设备的存储分区挂载时机较晚,或者定制ROM的存储权限逻辑有修改,导致getExternalFilesDir初始化失败、临时文件创建异常。
- 如果
- 拍照回调的状态完全未校验
现有onActivityResult没有对请求码、结果码做任何判断:- 如果用户拍照中途取消,或者相机应用写入文件失败,回调的
resultCode不会是成功状态,但现有代码还是会尝试读取指定路径的文件。 - 部分定制ROM的相机应用,即使你传入了
EXTRA_OUTPUT的URI,也不会主动往指定路径写入完整照片,仅会在返回的Intent中携带低分辨率缩略图,这种场景下指定路径根本不会生成目标文件,自然解码不到有效Bitmap。
- 如果用户拍照中途取消,或者相机应用写入文件失败,回调的
- Bitmap解码的逻辑缺陷
直接调用BitmapFactory.decodeFile读取原图,没有做任何尺寸压缩:
部分设备拍摄的照片分辨率极高,直接解码会因为内存不足直接返回null,这也是var_Bitmap为null的常见诱因。
另外现有代码解码完成后立刻删除目标文件,如果存在异步加载的逻辑,后续读取时文件已经被删除,也会触发异常。
修复方向
- 所有可能为null的对象全部加校验:如果
storageDir为null,就 fallback 到应用内部缓存目录getCacheDir()创建临时文件,同时捕获空指针异常,避免pictureFilePath赋值失败。 onActivityResult首先校验请求码为自定义的2、且结果码为Activity.RESULT_OK,再执行后续的文件读取逻辑。- 解码Bitmap前先通过
BitmapFactory.Options读取图片宽高,计算合适的采样率压缩后再正式解码,避免内存不足。 - 增加兜底逻辑:如果指定路径的文件不存在,就尝试从回调返回的Intent中读取缩略图,兼容部分ROM的特殊实现。
内容的提问来源于stack exchange,提问作者djac
相关产品推荐
相关产品推荐

