本文导读:在安卓手机上,安装或者卸载一个 App,会涉及到本地存储系统的哪些目录结构变化?作为开发人员,如何恰当地存储应用相关的信息?相关存储目录的生命周期、访问方式和访问权限又是怎样的呢?带着这些问题,希望读完这篇文章,你能够有所收获。
内部存储空间中的应用私有目录
对于设备中每一个安装的 App,系统都会在内部存储空间的 data/data 目录下以应用包名为名字自动创建与之对应的文件夹。这个文件夹用于 App 中的 WebView 缓存页面信息,SharedPreferences 和 SQLiteDatabase 持久化应用相关数据等。
对于没有 Root 过的手机,普通用户是无法查看 data/data 目录内容的。不过开发人员可以使用模拟器调试应用,并通过 DDMS(Dalvik Debug Monitor Server)提供的 File Explorer 工具查看模拟器设备的存储空间。
操作路径:
第一步:Android Studio --> Tools --> Android --> Android Device Monitor;
第二步:Window --> Show View --> Android --> File Explorer。
Android SDK 提供有如下方法可以获取并操作内部存储空间下应用私有目录文件的方,都位于 Application Context 中,供开发者直接调用:
getFilesDir():
getCacheDir():
deleteFile()
fileList()
等等,也可以通过 Environment 类访问:
Environment.getDataDirectory();
注意:当用户卸载 App 时,系统自动删除 data/data 目录下对应包名的文件夹及其内容。
外部存储空间中的应用私有目录
考虑内部存储空间容量有限,普通用户不能直接直观地查看目录文件等其他原因,Android 在外部存储空间中也提供有特殊目录供应用存放私有文件,文件路径为:
/storage/emulated/0/Android/data/app package name
备注:一般设备都有内置 SD 卡,同时也提供外部 SD 卡拓展,可能对应路径的目录名有所差异。
值得注意的是,与内部存储空间的应用私有目录不同的是:
第一,默认情况下,系统并不会自动创建外部存储空间的应用私有目录。只有在应用需要的时候,开发人员通过 SDK 提供的 API 创建该目录文件夹和操作文件夹内容。
第二,自 Android 7.0 开始,系统对应用私有目录的访问权限进一步限制。其他 App 无法通过 file:// 这种形式的 Uri 直接读写该目录下的文件内容,而是通过 FileProvider 访问。(关于这个内容,接下来再写一篇文章专门说说 7.0 的适配问题,欢迎关注我的微信公众号:安卓笔记侠。)
第三,宿主 App 可以直接读写内部存储空间中的应用私有目录;而在 4.4 版本开始,宿主 App 才可以直接读写外部存储空间中的应用私有目录,使开发人员无需在 Manifest 文件中或者动态申请外部存储空间的文件读写权限。
而相同点在于:同属于应用私有目录,当用户卸载 App 时,系统也会自动删除外部存储空间下的对应 App 私有目录文件夹及其内容。
同样,Android SDK 中也提供有便捷的 API 供开发人员直接操作外部存储空间下的应用私有目录:
getExternalFilesDir()
getExternalCacheDir()
等等,当然,也可以通过 Environment 类间接操作,只不过需要向用户申请操作权限:
Environment.getExternalStorageDirectory();
类似于 File 和 Cache 默认分类目录,开发人员也可以在应用私有目录中创建属于自己的自定义目录,方便于分类存储应用相关文件。
值得注意的一点是,对于外部存储空间下的应用私有目录文件,由于普通用户可以自由修改和删除,开发人员在使用时,一定要做好判空处理和异常捕获,防止应用崩溃退出!
外部存储空间中的公共目录
通常来说,应用涉及到的持久化数据分为两类:应用相关数据和应用无关数据。前者是指专供宿主 App 使用的数据信息,比如一些应用的配置信息,数据库信息,缓存文件等。当应用被卸载,这些信息也应该被随之删除,避免存储空间产生不必要的占用。
相对而言,后者更偏向于这类信息:当应用被卸载,用户仍然希望保留于设备当中的信息。常见如,拍照类应用的图片文件,用户是使用浏览器手动下载的文件等。
显然,无论是内部存储空间,还是外部储存空间,上述两个应用私有目录由于其特有的生命周期(随着应用卸载而自动清除)只适合存储应用相关数据。
或者从访问权限上来说,应用无关数据应该是宿主应用希望与其他应用共享这些数据的,应该存放在外部存储空间的公共目录文件夹下。
外部存储空间已经为用户默认分类出一些公共目录。开发人员可以通过 Environment 类提供的方法直接获取相应目录的绝对路径,传递不同的 type 参数类型即可:
Environment.getExternalStoragePublicDirectory(String type);
Envinonment 类提供诸多 type 参数的常量,比如:
DIRECTORY_MUSIC:Music
DIRECTORY_MOVIES:Movies
DIRECTORY_PICTURES:Pictures
DIRECTORY_DOWNLOADS:Download
等等,以第一个常量为例,音乐类别的公共目录绝对路径为:/storage/emulated/0/Music。如果你使用文件管理器打开设备的外部存储空间的话,均可以看到这些公共目录文件夹。
面对如此诸多的默认类别,开发人员在保存自己应用的公共文件时,也要养成良好的习惯,将要保存的数据分门别类地保存在不同公共目录下。当然,你也可以在公共目录下再次创建属于自己应用的目录,便于管理。
注意:访问外部存储空间时记得申请读写权限!
外部存储空间中的其他目录
一般来说,利用两种应用私有目录和公共目录便能够存储应用中需要保存的数据和文件。如果这些还不够的话,那一定是你的开发姿势不对。在 Code Review 的前提下,如果还是不够的话,还可以在外部存储空间自由创建其他目录,通过这个方式获取外部存储空间的绝对路径,然后操作文件:
Environment.getExternalStorageDirectory();
小结
使用应用私有目录保存应用相关数据,使用公共目录保存应用无关数据(共享数据)。无论哪种情况,都需要做好数据分类保存,便于清除等统一管理。随便打开手机上的几个应用,不难发现,很多应用都包含一个清理缓存的功能。事实上,开发人员清理的就是应用相关数据,也就是应用私有目录下的文件。
考虑到外部存储空间上的内容可能被用户手动删除,或者卸载拓展 SD 卡等不可控因素,操作前记得使用 Environment 类提供的 API 方法判断容量是否充足、文件是否存在等情况,做好异常捕获,减少应用崩溃率。相信这一定是一个良好的习惯。
更多存储选项和存储框架,参考开发者官网:
API Guides/Data Storage
API Guides/Provider