一、总结(Android10之前)
路径取得方法 | APP专用 | 非root用户可见 | APP卸载时 | |
---|---|---|---|---|
内部数据空间 | Context.getFilesDir() | yes | no | 消失 |
内部缓存空间 | Context.getCacheDir() | yes | no | 消失 |
外部数据空间 | Context.getExternalFilesDir(String type) | yes | yes | 消失 |
外部缓存空间 | Context.getExternalCacheDir() | yes | yes | 消失 |
外部公开空间 | Environment.getExternalStorageDirectory() | no | yes | 不消失 |
外部公开共享空间 | Environment.getExternalStoragePublicDirectory(String type) | no | yes | 不消失 |
内部空间
只有APP自己可以访问,其他APP和手机用户都不可以见。卸载消失。
外部私有空间
APP自己,手机用户,其他授权APP可以访问。卸载消失
外部公开空间
,所有APP和用户都可以访问。卸载不消失。
测试:
Context.getFilesDir() :/data/data/com.example/files
Context.getCacheDir() :/data/data/com.example/cache
Context.getExternalCacheDir() :/storage/emulated/0/Android/data/com.example/cache
Context.getExternalFilesDir() :/storage/emulated/0/Android/data/com.example/files
Environment.getExternalStorageDirectory() :/storage/emulated/0
Environment.getExternalStoragePublicDirectory() :/storage/emulated/0/
其中,除了外部存储公共空间以外,其他目录无需存储权限就可访问。
1.内部存储空间中的应用私有目录
路径取得方法 | APP专用 | 非root用户可见 | APP卸载时 | |
---|---|---|---|---|
内部数据空间 | Context.getFilesDir() | yes | no | 消失 |
内部缓存空间 | Context.getCacheDir() | yes | no | 消失 |
对于设备中每一个安装的 App,系统都会在内部存储空间的 data/data 目录下以应用包名为名字自动创建与之对应的文件夹。这个文件夹用于 App 中的 WebView 缓存页面信息,SharedPreferences 和 SQLiteDatabase 持久化应用相关数据等。
对于没有 Root 过的手机,普通用户是无法查看 data/data 目录内容的。不过开发人员可以使用模拟器调试应用,并通过 DDMS(Dalvik Debug Monitor Server)提供的 File Explorer 工具查看模拟器设备的存储空间。
当设备的内部存储空间不足时,Android 可能会删除
Context.getCacheDir()
下的文件以回收空间。
当用户卸载 App 时,系统自动删除 data/data 目录下对应包名的文件夹及其内容。
2.外部存储空间中的应用私有目录
路径取得方法 | APP专用 | 非root用户可见 | APP卸载时 | |
---|---|---|---|---|
外部数据空间 | Context.getExternalFilesDir() | yes | yes | 消失 |
外部缓存空间 | Context.getExternalCacheDir() | yes | yes | 消失 |
考虑内部存储空间容量有限,普通用户不能直接直观地查看目录文件等其他原因,Android 在外部存储空间中也提供有特殊目录供应用存放私有文件,文件路径为:
/storage/emulated/0/Android/data/app包名目录
值得注意的是,与内部存储空间的应用私有目录不同的是:
- 默认情况下,系统并不会自动创建外部存储空间的应用私有目录。只有在应用需要的时候,开发人员通过 SDK 提供的 API 创建该目录文件夹和操作文件夹内容。
-
自 Android 7.0 开始,系统对应用私有目录的访问权限进一步限制。其他 App 无法通过 file:// 这种形式的 Uri 直接读写该目录下的文件内容,而是通过 FileProvider 访问。
-
系统媒体扫描程序不会读取这些目录中的文件,
但是其他应用依然可以对该目录下的文件读写
,普通用户可以
自由修改和删除
,开发人员在使用时,一定要做好判空处理和异常捕获,防止应用崩溃退出! -
Context.getExternalCacheDir()
当内置存储的空间不足时将系统自动被清除
- Android 4.4以后访问该目录不再需要权限了
而相同点在于:
同属于应用私有目录,当用户卸载 App 时,系统也会自动删除外部存储空间下的对应 App 私有目录文件夹及其内容。
3.外部存储空间中的公共目录
路径取得方法 | APP专用 | 非root用户可见 | APP卸载时 | |
---|---|---|---|---|
外部公开空间 | Environment.getExternalStorageDirectory() | no | yes | 不消失 |
外部公开共享空间 | Environment.getExternalStoragePublicDirectory() | no | yes | 不消失 |
从访问权限上来说,应用无关数据应该是宿主应用希望
与其他应用共享这些数据
,应该存放在外部存储空间的公共目录文件夹下。
外部存储空间已经为用户
默认分类出一些公共目录
。开发人员可以通过
Environment
类提供的方法直接获取相应目录的绝对路径,传递不同的 type 参数类型即可:
Environment.getExternalStoragePublicDirectory(String type);
Envinonment
类提供诸多 type 参数的常量,比如:
- DIRECTORY_MUSIC:/storage/emulated/0/Music
- DIRECTORY_MOVIES:/storage/emulated/0/Movie
- DIRECTORY_PICTURES:/storage/emulated/0/Pictures
- DIRECTORY_DOWNLOADS: /storage/emulated/0/Download
- DIRECTORY_DOCUMENTS: /storage/emulated/0/Documents
还可以在外部存储空间自由创建其他目录,通过这个方式获取
外部存储空间的绝对路径
,然后操作文件:
Environment.getExternalStorageDirectory();
有个小技巧,无论外部内部,
只要路径中有包名,那么就是私有的,而且是随着程序的卸载而被删除的,有包名的路径均是Context中的方法,而公有的路径均是Environment调用的,卸载不会删除。
二、Android 10和Android 11
Android 10之前,外部存储区的内容主要以两种形式存在,一种是由应用的包名命名,归属于特定应用目录下的内容,另一种是存储在公共存储区域的内容。
在Android 10 中,Google首次引入了分区存储,将公共区域划分成了不同的集合,并且在媒体文件和其他文档之间建立了清楚的分割。经过划分之后应用不可以随意访问外部存储区中的文件,而只能访问媒体文件。如果想访问包含更多细节数据的其他文档,应用专门向用户申请有关文档的访问权限。
分区存储是需要以 Android 10 为目标平台的,系统默认强制执行。如果在 AndroidManifest 中添加了 requestLegacyExternalStorage=true 标志,就可以不受此限制。但是当 target API 更新为 30 后,系统会忽略该配置。
如果有数据需要迁移,可以在 AndroidManifest 中将 preserveLegacyExternalStorage 属性设为 true ,当用户升级到以 Android 11 为目标平台时,这个配置就会生效。具体而言,这个配置在用户重新安装该应用前都是有效的。
针对以 Android 11 为目标平台的应用 (targetSdkVersion = 30) ,WRITEEXTENRNALSTORAGE 和 WRITEMEDIASTORAGE 不再提供其他任何访问权限 。
某些应用的核心功能可能需要访问大量的文件,例如文件管理操作、备份和恢复操作等等,此时就需要申请 MANAGEEXTERNALSTORAGE 权限。我们可以通过使用 ACTIONMANAGEALLFILESACCESS_PERMISSION intent 操作将用户引导至一个系统设置页面,让用户为应用授予所有文件的管理权限。