Android调用Environment.getExternalStorageDirectory()返回null问题求助
问题产生原因
- Android权限适配不到位:
- Android 6.0(API 23)开始,
READ_EXTERNAL_STORAGE属于运行时权限,仅在AndroidManifest中静态声明不生效,必须在访问存储前主动向用户申请授权,未获得授权时file.listFiles()会直接返回null。 - Android 13(API 33)开始,
READ_EXTERNAL_STORAGE权限已被废弃,读取音频文件需要申请专门的READ_MEDIA_AUDIO权限,再申请旧的存储权限无法获得访问权限。
- Android 6.0(API 23)开始,
- 分区存储适配问题:
当targetSdkVersion >= 29(Android 10)时,系统默认开启分区存储限制,Environment.getExternalStorageDirectory()已被废弃,即使获得旧存储权限也无法直接访问公共目录,调用后返回的目录没有读取权限,listFiles()返回空。 - 代码本身存在空指针隐患:
原代码未对file.listFiles()的返回值做非空校验,当遇到无权限目录、空目录、不存在的目录时,listFiles()直接返回null,后续遍历会触发空指针异常,导致函数异常返回null。
解决方法
- 分版本适配动态权限
- AndroidManifest中补充对应权限声明:
<!-- 适配Android 13以下版本 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- 适配Android 13及以上版本 --> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />- 在调用
displaySongs()方法前,先检查对应权限是否已获得,未授权则先动态申请权限,用户同意后再执行歌曲扫描逻辑。
- 适配分区存储规则
- 若targetSdkVersion为29,可在AndroidManifest的application节点临时添加
android:requestLegacyExternalStorage="true"关闭分区存储(仅适用于Android 10,Android 11及以上版本无效)。 - Android 11及以上版本推荐使用MediaStore API查询音频文件,不需要遍历整个存储目录,性能更高且符合系统权限要求。
- 若targetSdkVersion为29,可在AndroidManifest的application节点临时添加
- 修复代码空指针隐患,修改后的
findSong函数如下:
public ArrayList<File> findSong(File file){ ArrayList<File> arrayList = new ArrayList<>(); File[] files = file.listFiles(); // 新增空判断,避免空指针异常 if (files == null) { return arrayList; } for(File singleFile: files){ if(singleFile.isDirectory() && !singleFile.isHidden()){ arrayList.addAll(findSong(singleFile)); } else { String fileName = singleFile.getName().toLowerCase(); if(fileName.endsWith(".mp3") || fileName.endsWith(".wav")){ arrayList.add(singleFile); } } } return arrayList; }
内容的提问来源于stack exchange,提问作者BKarayilmaz
相关产品推荐
相关产品推荐

