Android 9创建目录后应用崩溃的原因及解决方法
Android 9设备目录创建引发崩溃的问题分析与解决
问题背景
我开发的应用包含一个服务,会在onStartCommand()或onDestroy()阶段保存文件。在服务的onCreate()方法中,我会检查应用目录及其子目录是否存在,若不存在则创建路径。但在Android 9.0设备上出现异常:调用exists()方法后,应用直接崩溃,重启后却能正常运行。尝试用try-catch包裹exists()也无法捕获异常,而Android 12设备完全没有这个问题。
相关代码:
@Override public void onCreate() { // 其他初始化操作... File dir = new File(myDirectory); /* myDirectory为应用目录完整路径,示例: /storage/emulated/0/directory/subdirectory */ if(!dir.exists()) { try { if(!dir.mkdirs()) { // 处理创建失败逻辑 } } catch (Exception e) { // 异常处理逻辑 } } }
问题原因
- Android 9存储权限机制差异:Android 9(API 28)是存储权限模型的过渡版本,默认启用的存储沙盒机制在处理多级外部目录时可能存在隐性权限冲突。当父目录未被正确授权时,
exists()的底层实现可能触发Java层无法捕获的Native级异常(如SELinux权限错误),直接导致应用崩溃。 exists()的状态判断偏差:你观察到的exists()创建路径是误解——File.exists()本身不会创建目录,但旧设备的存储服务可能存在状态同步延迟,导致路径状态判断错误,后续mkdirs()操作触发系统层面的崩溃。- 异常捕获范围不足:普通的
try-catch(Exception e)无法捕获JNI抛出的Native异常,这类异常不会进入Java层的异常处理流程,直接导致应用终止。
解决方法
1. 适配旧版存储权限模型
在AndroidManifest.xml的application标签中添加requestLegacyExternalStorage属性,强制Android 9及以下设备使用旧版存储权限逻辑,避免沙盒机制的冲突:
<application ... android:requestLegacyExternalStorage="true"> </application>
2. 简化目录创建逻辑
直接调用mkdirs()代替exists()判断,因为mkdirs()会自动处理目录已存在的情况(此时返回true),同时避免状态判断错误:
@Override public void onCreate() { // 其他初始化操作... File dir = new File(myDirectory); // 直接创建目录,已存在时返回true if (!dir.mkdirs()) { Log.e("DirInit", "目录创建失败:" + myDirectory); // 这里可以添加降级处理,比如切换到内部存储 } }
3. 扩大异常捕获范围
如果需要保留判断逻辑,改用try-catch(Throwable t)捕获所有类型的异常(包括Native层异常),并添加降级处理:
@Override public void onCreate() { // 其他初始化操作... File dir = new File(myDirectory); try { if (!dir.exists()) { if (!dir.mkdirs()) { Log.e("DirInit", "mkdirs执行失败"); } } } catch (Throwable t) { Log.e("DirInit", "目录处理出错", t); // 降级到应用内部存储,无需额外权限 dir = getFilesDir(); dir.mkdirs(); } }
4. 使用应用私有存储目录
如果存储的是应用私有文件,优先使用内部存储或外部私有目录,这些路径不需要额外的存储权限,彻底规避权限问题:
// 获取应用外部私有子目录,无需申请READ/WRITE_EXTERNAL_STORAGE权限 File dir = getExternalFilesDir("subdirectory"); if (!dir.exists()) { dir.mkdirs(); }
内容的提问来源于stack exchange,提问作者Georgios Tsakiridis
相关产品推荐
相关产品推荐

