使用存储访问框架打开文件

Android 4.4(API 级别 19)引入了存储访问框架 (SAF)。SAF 允许用户在其所有首选文档存储提供程序中浏览和打开文档、图片和其他文件。通过易用的标准界面,用户可以在各种应用和提供程序中以一致的方式浏览文件和访问近期文件。

云存储服务或本地存储服务可实现用于封装其服务的 DocumentsProvider,从而加入此生态系统。需要访问提供程序文档的客户端应用只需几行代码即可与 SAF 集成。

SAF 包含以下元素:

  • 文档提供程序:一种内容提供程序,可让存储服务(如 Google 云端硬盘)显示其管理的文件。文档提供程序以 DocumentsProvider 类的子类形式实现。文档提供程序的架构基于传统的文件层次结构,但其实际的数据存储方式由您决定。Android 平台包含若干内置的文档提供程序,如 Downloads、Images 和 Videos。
  • 客户端应用:一个自定义应用,它会调用 ACTION_CREATE_DOCUMENTACTION_OPEN_DOCUMENTACTION_OPEN_DOCUMENT_TREE intent 操作并接收文档提供程序返回的文件。
  • 选择器:一个系统界面,可让用户访问所有文档提供程序中满足客户端应用搜索条件的文档。

SAF 提供以下功能:

  • 让用户浏览所有文档提供程序的内容,而不仅仅是单个应用的内容。
  • 让您的应用可以获得对文档提供程序所拥有文档的长期、持续访问权限。通过此访问权限,用户可以添加、编辑、保存和删除提供程序中的文件。
  • 支持多个用户账号和临时根目录,如只有在插入 U 盘后才会出现的“USB 存储提供程序”。

概览

SAF 的核心是一个内容提供程序,它是 DocumentsProvider 类的一个子类。在文档提供程序内,数据结构采用传统的文件层次结构:

数据模型

图 1. 文档提供程序数据模型。根指向单个文档,然后该文档启动树的扇出。

请注意以下几点:

  • 每个文档提供程序都会报告一个或多个根目录,它们是探索文档树的起点。每个根目录都有一个唯一的 COLUMN_ROOT_ID,并且指向一个表示该根目录下内容的文档(目录)。根目录采用动态设计,以支持多个帐号、临时 USB 存储设备或用户登录和退出等用例。
  • 每个根目录下都只有一个文档。该文档指向 1 到 N 个文档,其中每个文档又可指向 1 至 N 个文档。
  • 每个存储后端都会使用唯一的 COLUMN_DOCUMENT_ID 来引用各个文件和目录,以便将其呈现出来。文档 ID 是唯一的,发布后便不会更改,因为它们用于所有设备重新启动之间的永久性 URI 授权。
  • 文档可以是具有特定 MIME 类型的可打开文件,也可以是包含其他文档且具有 MIME_TYPE_DIR MIME 类型的目录。
  • 每个文档可拥有不同的功能,具体在 COLUMN_FLAGS 中指定。例如,FLAG_SUPPORTS_WRITEFLAG_SUPPORTS_DELETEFLAG_SUPPORTS_THUMBNAIL。多个目录中可包含相同的 COLUMN_DOCUMENT_ID

控制流

文档提供程序数据模型基于传统的文件层次结构。不过,只要可以使用 DocumentsProvider API 访问数据,您实际上可以采用自己喜欢的任何方式存储数据。例如,您可以使用基于标记的云端存储空间来存储数据。

图 2 展示的是照片应用可能会如何利用 SAF 来访问存储的数据:

应用

图 2. 存储访问框架流程。

请注意以下几点:

  • 在 SAF 中,提供程序和客户端并不直接交互。客户端会请求与文件交互的权限,即读取、编辑、创建或删除文件。
  • 当应用(在本示例中为照片应用)触发 intent ACTION_OPEN_DOCUMENTACTION_CREATE_DOCUMENT 时,互动便会开始。intent 可以包含用于进一步优化条件的过滤器,例如“为我提供所有 MIME 类型为‘图片’的可打开文件”。
  • 当 intent 触发后,系统选择器会联络每个已注册的提供程序,并向用户显示匹配内容的根目录。
  • 选择器会为用户提供标准的文档访问界面,即使底层文档提供程序大相径庭也是如此。例如,图 2 展示了一个 Google 云端硬盘提供程序、一个 USB 提供程序和一个云提供程序。

在图 3 中,用户从搜索图片时打开的选择器中选择“Downloads”文件夹。该选择器还会显示可供客户端应用使用的所有根目录。

系统选择器中的文件夹选择屏幕截图

图 3. 显示“Downloads”文件夹被选为搜索位置的选择器。

在用户选择 Downloads 文件夹后,系统会显示图片。图 4 显示了此过程的结果。用户现在可以以提供程序和客户端应用支持的方式与图片进行交互。

Downloads 文件夹的屏幕截图

图 4. 存储在“Downloads”文件夹中的图片,与在系统选择器中看到的一样。

编写客户端应用

在 Android 4.3 及更低版本中,如果您想让应用从其他应用中检索文件,则该应用必须调用 ACTION_PICKACTION_GET_CONTENT 等 intent。然后,用户选择一个要从中选择文件的应用。所选应用必须提供一个界面,以便用户浏览可用文件并从中选择。

在 Android 4.4(API 级别 19)及更高版本中,您还可以选择使用 ACTION_OPEN_DOCUMENT intent,该 intent 会显示一个由系统控制的选择器界面,以便用户浏览其他应用提供的所有文件。借助此界面,用户便可从任何受支持的应用中选择文件。

在 Android 5.0(API 级别 21)及更高版本中,您还可以使用 ACTION_OPEN_DOCUMENT_TREE intent,该 intent 可让用户选择客户端应用访问的目录。

注意 ACTION_OPEN_DOCUMENT 不能替代 ACTION_GET_CONTENT。您使用的方法取决于应用的需求:

  • 如果您希望应用读取或导入数据,请使用 ACTION_GET_CONTENT。使用此方法时,应用会导入数据(如图片文件)的副本。
  • 如果您希望应用获得对文档提供程序所拥有文档的长期、持久性访问权限,请使用 ACTION_OPEN_DOCUMENT。例如,照片编辑应用可让用户编辑存储在文档提供程序中的图片。

如需详细了解如何使用系统选择器界面支持浏览文件和目录,请参阅关于访问文档和其他文件的指南。

其他资源

如需详细了解文档提供程序,请参考以下资源:

示例

视频