为了提高文件的规整程度并让用户可以更好地控制他们的文件,Android 10 为应用引入了名为 "分区存储" 的新范式。分区存储改变了应用在外置存储中保存和访问文件的方式,为了帮您迁移应用并支持分区存储,我们概括了常见用例的最佳实践并分享给大家。在我们过去的文章推送里已经向您介绍了处理媒体类文件的常见用例和最佳实践,本篇将继续带您了解处理非媒体文件的用例和最佳实践,供您参考。
这部分内容描述了处理非媒体文件的一些常见用例,并概要说明了应用可以使用的方法。我们对下述各种用例在不同系统版本的实践也做了一个小结图片,供您参考:
打开文档文件
使用 ACTION_OPEN_DOCUMENT intent 来要求用户通过系统选择器选择需要打开的文件。如果您想要过滤系统选择器展示给用户的文件类型,可以使用 setType() 或 EXTRA_MIME_TYPES。
- ACTION_OPEN_DOCUMENT
https://developer.android.google.cn/reference/android/content/Intent#ACTION_OPEN_DOCUMENT - setType()
https://developer.android.google.cn/reference/android/content/Intent#setType(java.lang.String) - EXTRA_MIME_TYPES
https://developer.android.google.cn/reference/android/content/Intent#EXTRA_MIME_TYPES
举例来说,您可以通过以下代码找到所有的 PDF、ODT 和 TXT 文件:
Kotlin 代码
startActivityForResult(
Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
putExtra(Intent.EXTRA_MIME_TYPES, arrayOf(
"application/pdf", // .pdf
"application/vnd.oasis.opendocument.text", // .odt
"text/plain" // .txt
))
},
REQUEST_CODE
)
Java 代码
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {
"application/pdf", // .pdf
"application/vnd.oasis.opendocument.text", // .odt
"text/plain" // .txt
});
startActivityForResult(intent, REQUEST_CODE);
从旧的存储位置迁移现有文件
如果一个目录既不是特定应用的目录,也不是公开共享目录,那么它就会被视为旧版存储位置。如果您的应用创建或使用位于旧版存储位置的文件,我们建议您将应用的文件迁移至可被分区存储访问的位置,同时对应用进行必要的修改,以使用分区存储中的文件。
保留对旧版存储位置的访问以进行数据迁移
您的应用需要保留对旧版存储位置的访问,以便可以将任何文件迁移至可被分区存储访问的位置。您应该的使用的方法取决于您应用的目标 API 级别。
如果您的应用目标平台为 Android 11
- 使用 preserveLegacyExternalStorage 标志来保留旧版存储模型,这样您的应用就可以在用户将应用升级为目标平台为 Android 11 的新版本时迁移用户数据。
注意: 如果您使用 preserveLegacyExternalStorage,保持旧存储模型的效果只会在用户卸载应用之前有效。如果用户在运行 Android 11 的设备上安装或重装您的应用,则无论 preserveLegacyExternalStorage 的值是什么,您的应用都无法停用分区存储模型。
- 继续停用分区存储,以便您的应用可以继续访问运行 Android 10 的设备上旧版存储位置中的文件。
- 保留旧版存储模型
https://developer.android.google.cn/preview/privacy/storage#migrate-data-for-scoped-storage - 停用分区存储
https://developer.android.google.cn/training/data-storage/use-cases#opt-out-scoped-storage
如果您的应用目标平台为 Android 10
停用分区存储,以便您可以更轻松地在多个 Android 版本间保持应用行为不变。
迁移应用数据
当您的应用已经做好迁移的准备时,使用以下方法:
- 检查您应用在工作中是否使用了位于 /sdcard/ 目录或其任何子目录中的文件;
- 将应用的所有私有文件从现在的 /sdcard/ 下的目录中移动至 getExternalFilesDir() 方法所返回的目录中;
- 将所有共享的非媒体文件从现在的 /sdcard/ 下的目录中移动至 Downloads/ 目录下的一个应用专用子目录;
- 从 /sdcard/ 目录移除应用程序的旧存储目录。
- getExternalFilesDir()
https://developer.android.google.cn/reference/android/content/Context#getExternalFilesDir(java.lang.String)
与其他应用共享内容
您可以使用 FileProvider 分享应用的文件给某个其他应用。而对于那些需要互相之间分享文件的所有应用,我们推荐为每一个应用使用内容提供程序,然后在将应用添加到集合中时同步数据。
- 使用 FileProvider
https://developer.android.google.cn/training/secure-file-sharing - 内容提供程序
https://developer.android.google.cn/guide/topics/providers/content-provider-basics
缓存非媒体文件
您应使用的方法取决于需要缓存的文件类型。
- 小型文件或者包含敏感信息的文件: 使用 Context#getCacheDir()
https://developer.android.google.cn/reference/android/content/Context#getCacheDir() - 大型文件或者不包含敏感信息的文件: 使用 Context#getExternalCacheDir()
https://developer.android.google.cn/reference/android/content/Context#getExternalCacheDir()
暂时停用分区存储
在您的应用完全兼容分区存储之前,您可以通过以下方法之一停用分区存储:
- 目标平台设置为 Android 9 (API level 28) 或更低。
- 如果您的目标平台为 Android 10 (API level 29) 或者更高版本,将您应用 manifest 中的 requestLegacyExternalStorage 属性设置为 "true":
<manifest ... >
<!-- 该属性在目标 API 为 Android 10 或更高版本的应用中默认为 "false" -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
注意: 在您将应用的目标 API 更新为 Android 11 (API level 30) 后,如果应用运行在 Android 11 的设备上,系统会忽略 requestLegacyExternalStorage 属性。所以您的应用必须为支持分区存储做好准备,并为使用该设备的用户迁移数据。
- 系统会忽略 requestLegacyExternalStorage 属性
https://developer.android.google.cn/preview/privacy/storage#scoped-storage - 迁移数据
https://developer.android.google.cn/training/data-storage/use-cases#migrate-legacy-storage
为了测试目标 API 为 Android 9 及更低版本的应用在使用分区存储时的行为,您可以通过设置 requestLegacyExternalStorage 的值设置为 false 来使应用选择启用行为。如果要在 Android 11 设备上进行测试,则还可以使用应用兼容性标志在使用或不使用分区存储的情况下测试应用的行为。
了解有关 Android 平台文件存储与访问的详细信息,请参阅以下资源:
如果您想了解更多最新关于使用存储空间的最佳实践,请在 Android 官方中文文档网站或点击屏末阅读原文查看。
- Android 存储用例和最佳做法 - Android 官方中文文档
https://developer.android.google.cn/training/data-storage/use-cases?hl=zh-CN