Android API31下Documents目录文件存在但应用内无法查看问题
应用无法读取Documents目录下备份文件的修复方案
问题根因定位
从实现代码和现象看,问题集中在三个方向:
- 安卓分区存储机制下权限配置缺失,无法通过文件路径直接访问公共存储目录
- 硬编码路径拼接存在兼容问题,传入文件选择器的路径和文件实际存储路径不匹配
- 自定义
FileChooserActivity内部存在过滤/逻辑错误,未正确加载目标目录下的json文件
分步修复方案
1. 补全存储权限与兼容配置
安卓系统从10版本开始引入分区存储,对公共目录的文件访问做了严格限制,需要先做权限适配:
- 在
AndroidManifest.xml中声明对应权限:
<!-- API 32及以下版本读外部存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- 安卓11+如需直接通过路径访问全量存储文件时添加,注意谷歌应用商店对该权限有审核规则 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
- 针对安卓10版本做临时兼容,在
<application>标签下添加属性:
<application ... android:requestLegacyExternalStorage="true" ...>
- 所有权限需要在代码中动态申请,用户授权后再执行文件访问逻辑,不要仅在Manifest声明就直接调用。
2. 修正路径处理逻辑,增加合法性校验
现有代码硬编码/作为路径分隔符,且未做目录存在性、可读性校验,容易出现路径不匹配问题,替换为以下实现:
// 用File.separator替代硬编码斜杠,兼容不同系统的路径格式 public static final String BACKUP_PATH = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + File.separator + "Kalendarz zmianowy" + File.separator + "Kopia zapasowa" + File.separator; File backupDir = new File(BACKUP_PATH); // 打印实际路径核对,确认和手动在文件管理器看到的目录路径完全一致 Log.d("BackupCheck", "目标目录路径:" + backupDir.getAbsolutePath()); if (!backupDir.exists()) { // 目录不存在时递归创建所有父级目录 backupDir.mkdirs(); } if (backupDir.canRead()) { // 确认目录有读权限再启动文件选择器 Intent intent = new Intent(getActivity(), FileChooserActivity.class); intent.putExtra(FileChooserActivity.PATH, backupDir.getAbsolutePath()); getActivity().startActivityForResult(intent, ShiftCalendarApplication.REQUEST_CODE_BACKUP); } else { // 无读权限时先走权限申请流程 applyStoragePermission(); }
3. 排查自定义文件选择器逻辑
当前启动的是应用内自定义的FileChooserActivity而非系统文件选择器,需要检查组件内部实现:
- 确认组件没有配置文件后缀过滤规则,误将
.json格式的备份文件过滤不显示 - 确认组件加载文件列表时,是使用传入的
PATH参数构造File对象调用listFiles()获取文件列表,没有写死其他根目录 - 确认组件内部没有额外的路径拦截、权限判断逻辑,阻止了公共目录文件的加载
4. 推荐方案:替换为系统SAF文件选择器
自定义文件选择器适配多版本安卓存储机制成本很高,推荐直接使用系统自带的存储访问框架(SAF)实现文件选择,不需要申请额外存储权限,兼容性更好:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); // 仅过滤显示json格式文件 intent.setType("application/json"); // 安卓8及以上支持指定初始打开目录 Uri initialDirUri = Uri.fromFile(new File(BACKUP_PATH)); intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, initialDirUri); startActivityForResult(intent, ShiftCalendarApplication.REQUEST_CODE_BACKUP);
用户选择文件后,在onActivityResult回调中拿到返回的文件Uri,通过ContentResolver即可直接读取文件内容,不会出现路径不兼容、权限不足导致的文件不显示问题。
现象对照说明
两张截图的差异本质是:系统自带文件管理器拥有全存储访问权限,可以正常看到目录下的所有文件;应用内自定义选择器受权限、路径配置、自身逻辑限制,无法正确加载目录文件列表,才会显示空目录。
内容的提问来源于stack exchange,提问作者Tomasz Stępnik
相关产品推荐
相关产品推荐

