php网站模板带后台,a站app下载,中交建设集团天津公司网站,大连做网站的公司有哪些1 概述
Android 4.4#xff08;API 级别 19#xff09;引入了存储访问框架 (Storage Access Framework)。SAF让用户能够在其所有首选文档存储提供程序中方便地浏览并打开文档、图像以及其他文件。 用户可以通过易用的标准 UI#xff0c;以统一方式在所有应用和提供程序中浏…1 概述
Android 4.4API 级别 19引入了存储访问框架 (Storage Access Framework)。SAF让用户能够在其所有首选文档存储提供程序中方便地浏览并打开文档、图像以及其他文件。 用户可以通过易用的标准 UI以统一方式在所有应用和提供程序中浏览文件和访问最近使用的文件。 存储访问框架SAF包括以下内容
文档提供程序 ConentProvider的子类允许存储服务显示其管理的文件。 文档提供程序作为 DocumentsProvider 类的子类实现。文档提供程序的架构基于传统文件层次结构。Android 平台包括若干内置文档提供程序操作sd卡对应的为ExternalStorageProvider。客户端应用 就是我们平时的app它调用 ACTION_OPEN_DOCUMENT,ACTION_CREATE_DOCUMENT ,ACTION_OPEN_DOCUMENT_TREE这三种Intent的Action,来实现打开创建文档以及打开文档树。选取器 一种系统 UI我们称为DocumentUi,允许用户访问所有满足客户端应用搜索条件的文档提供程序内的文档。这个DocumentUI无桌面图标和入口只能通过上面的Intent访问。 在SAF框架中我们的app应用和DocumentProvider之间并不产生直接的交互而是通过DocumentUi进行。
2 SAF框架的使用
上文已经讲过SAF框架的使用是通过DocumentUI的选择器来间接进行的没法直接进行文件的操作。 使用方法如下
2.1 打开文件
private static final int READ_REQUEST_CODE 42;
...public void performFileSearch() {Intent intent new Intent(Intent.ACTION_OPEN_DOCUMENT);//过滤器只显示可以打开的结果intent.addCategory(Intent.CATEGORY_OPENABLE);//要搜索通过已安装的存储提供商提供的所有文档//intent.setType(*/*);startActivityForResult(intent, READ_REQUEST_CODE);}Overridepublic void onActivityResult(int requestCode, int resultCode,Intent resultData) {//使用resultdata.getdata ( )提取该URIif (requestCode READ_REQUEST_CODE resultCode Activity.RESULT_OK) {Uri uri null;if (resultData ! null) {uri resultData.getData();Log.i(TAG, Uri: uri.toString());showImage(uri);}}
}返回Uri
content://com.android.externalstorage.documents/document/primary%3ADCIM%2FCamera%2FIMG20190607162534.jpg2.2 打开文件树
Intent intent new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, OPEN_TREE_CODE);private void handleTreeAction(Intent data){Uri treeUri data.getData();//授予打开的文档树永久性的读写权限final int takeFlags intent.getFlags() (Intent.FLAG_GRANT_READ_URI_PERMISSION| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);getContentResolver().takePersistableUriPermission(uri, takeFlags);//使用DocumentFile构建一个根文档之后的操作可以在该文档上进行mRoot DocumentFile.fromTreeUri(this, treeUri);//显示结果toastshowToast( open tree uri treeUri);
}返回的Uri
content://com.android.externalstorage.documents/tree/primary%3AColorOS对于我们打开的文档树系统会赋予我们对该文档树下所有文档的读写权限因此我们可以自由的使用我们上面介绍的输入输出流或者文件的方式来进行读写该授权会一直保留到用户重启设备。但是有时候我们需要能够永久性的访问这些文件的权限而不是重启就需要重新授权因此我们使用了takePersistableUriPermission方法来保留系统对我们的uri的授权即使设备重启也不影响。我们可能保存了应用最近访问的 URI但它们可能不再有效 — 另一个应用可能已删除或修改了文档。 因此应该调用 getContentResolver().takePersistableUriPermission() 以检查有无最新数据。拿到了根目录的uri,我们就可用使用DocumentFile辅助类来方便的进行创建删除文件等操作了。
2.3 创建文件 ACTION_CREATE_DOCUMENT
private void createDocument(){Intent intent new Intent(Intent.ACTION_CREATE_DOCUMENT);//设置创建的文件是可打开的intent.addCategory(Intent.CATEGORY_OPENABLE);//设置创建的文件的minitype为文本类型intent.setType(text/*);//设置创建文件的名称注意SAF中使用minitype而不是文件的后缀名来判断文件类型。intent.putExtra(Intent.EXTRA_TITLE, 123.txt);startActivityForResult(intent,CREATE_DOCUMENT_CODE);
}private void handleCreateDocumentAction(Intent data){if (data null) {return;}BufferedWriter bw null;try {OutputStream os getContentResolver().openOutputStream(uri);bw new BufferedWriter(new OutputStreamWriter(os));bw.write( i am a text );showToast( create document succeed uri uri);} catch (IOException e) {e.printStackTrace();}finally {closeSafe(bw);}}2.4 编辑文档
在onActivityResult()中获取到Uri之后就可以对这个uri进行操作 private void alterDocument(Uri uri) {try {ParcelFileDescriptor pfd getContext().getContentResolver().openFileDescriptor(uri, w);FileOutputStream fileOutputStream new FileOutputStream(pfd.getFileDescriptor());fileOutputStream.write((Overwritten by MyCloud at System.currentTimeMillis() \n).getBytes());// Let the document provider know you re done by closing the stream.fileOutputStream.close()fileOutputStream.close();pfd.close();} catch (IOException e) {e.printStackTrace();}}2.5 删除文档
如果您获得了文档的 URI并且文档的 Document.COLUMN_FLAGS 包 SUPPORTS_DELETE便可以删除该文档。例如
DocumentsContract.deleteDocument(getContentResolver(), uri);2.6 DocumentFile类的使用
DocumentFile是google为了方便大家使用SAF进行文件操作而推出的帮助类。它的api和java的File类比较接近更符合一般用户的习惯且内部实质都是使用了DocumentsContact类的方法来对文件进行操作。也就是说我们也可以完全不使用DocumentFile而是使用DocumentsContact来完成SAF框架提供的文件操作DocumentFile提供了三个静态工厂方法来创建自身。
fromSingleUri,该方法需要传入一个SAF返回的指向单个文件的uri,我们的ACTION_OPEN_DOCUMENT,ACTION_CREATE_DOCUMENT返回的uri就是该类型其对应的实现类为ingleDocumentFile代表的是单个的文件。 fromTreeUri该方法传入指向文件夹的uri,我们的ACTION_OPEN_TREE返回的就是该类型其对应的实现类为TreeDocumentFile代表的是一个文件夹。 fromFile该方法传入普通的File类是对file类的一个模拟。
DocumentFile的方法总结如下
3 SAF框架原理
3.1 SAF框架的类关系图如下所示 由类关系图可以看出DocumentFile工具类最终是通过DocumentsContract来实现操作的而DocumentsContract最终操作的Provider是DocumentsProvider。DocumentsProvider有三类
ExternalStorageProvider是外置SD卡对应的ProviderDownloadStorageProvider是下载对应的Provider。
ExternalStorageProvidercom.android.externalstorage.documents DownloadStorageProvidercom.android.providers.downloads.documents MediaDocumentProvidercom.android.providers.media.documents
下面具体分析下创建修改删除文件的流程 可以看出DocumentFile辅助类最终也是通过DocumentsContract来操作DocumentsProvider
下面看下跳到选择PickerUI的流程 PickerUI最终也调到了DocumentsContract中。
3.2 DocumentProvider中的文档组织形式
在文档提供程序内数据结构采用传统的文件层次结构如下图所示 每个DocumentProvider都可能有1个或多个做为文档结构树的Root根目录每个根目录都有唯一的COLUMN_ROOT_ID,并且指向该根目录下表示内容的文档。每个根目录下都有一个文档该文档指向1到n个文档而其中的每个文档又可以指向1到N个文档从而形成树形的文档结构。每个Document都会有唯一的COLUMN_DOCUMENT_ID用以引用它们文档id具有唯一性并且一旦发放就不得更改因为它们用于所有设备重启过程中的永久性 URI 授权。文档可以是可打开的文件具有特定 MIME 类型或包含附加文档的目录具有 MIME_TYPE_DIR MIME 类型。每个文档都可以具有不同的功能如 COLUMN_FLAGS 所述。例如FLAG_SUPPORTS_WRITE、FLAG_SUPPORTS_DELETE 和 FLAG_SUPPORTS_THUMBNAIL。多个目录中可以包含相同的 COLUMN_DOCUMENT_ID。 Document: 3.3 自定义DocumentProvider
如果你希望自己应用的数据也能在documentsui中打开你就需要写一个自己的document provider。如果只是普通的文件操作则不需要这么定义 1)首先需要在Manifest中声明自定义的provider
2)实现DocumentProvider的基本接口
4 SAF框架总结
1. SAF框架并不是直接与与DocumentProvider直接打交道而是通过DocumentUI来间接操作。 2. 无论是通过Intent的方式还是通过辅助类DocumentFile来进行文件操作都需要获取uri这个uri只能通过DocumentUI来返回所以不是很方便。如果能接受通过DocumentUI来交互的用SAF框架基本可以替代原有的文件操作方法
本章节大概了解SAF框架我们下一章将对Android Q的沙箱模式(Scoped Storage)进行介绍