欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android11(30)/Android10(29)分区存储-存储访问框架(SAF)

程序员文章站 2022-06-25 09:17:38
概述存储访问框架(SAF)是在Android 4.4(API 级别 19)引入的。借助 SAF,用户可轻松打开文档、图像及其他文件。存储访问框架包含三部分:文档提供程序 — 文档提供程序以 DocumentsProvider 类的子类形式实现。Android 平台包含有内置文档提供程序,如 Downloads、Images 和 Videos。客户端应用 — 应用可以通过发送 ACTION_OPEN_DOCUMENT 或 ACTION_CREATE_DOCUMENT 的Intent来启动选择器,并....

Android11(30)/Android10(29)分区存储-存储访问框架(SAF)

概述

存储访问框架(SAF)是在Android 4.4(API 级别 19)引入的。借助 SAF,用户可轻松打开文档、图像及其他文件。

存储访问框架包含三部分:

  • 文档提供程序 — 文档提供程序以 DocumentsProvider 类的子类形式实现。Android 平台包含有内置文档提供程序,如 Downloads、Images 和 Videos。
  • 客户端应用 — 应用可以通过发送 ACTION_OPEN_DOCUMENTACTION_CREATE_DOCUMENT 的Intent来启动选择器,并可以接收文档提供程序返回的文件。
  • 选择器 — 系统界面,可让用户选择客户端应用期望格式的文档。

三者的关系如下图
Android11(30)/Android10(29)分区存储-存储访问框架(SAF)

客户端可以通过以下的Action来启动系统选择器,让用户做相关的操作:

  • ACTION_OPEN_DOCUMENT 打开用户选择的文件
  • ACTION_CREATE_DOCUMENT 在用户选择的位置创建文件
  • ACTION_OPEN_DOCUMENT_TREE 访问某个目录,在Android5.0(API 级别 21)首次引入。

创建应用并写入内容

我们以创建一个jpg文件写入内容为例,来看看如何使用SAF。

  • 通过 ACTION_CREATE_DOCUMENT的Intent启动系统选择器
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {    addCategory(Intent.CATEGORY_OPENABLE)    type = "image/jpeg"    putExtra(Intent.EXTRA_TITLE, "invoice.jpg")}startActivityForResult(intent, REQUEST_CODE_CREATE_FILE)
  • 用户选择某个目录创建invoice.jpg文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OlrfzaR2-1600607710842)(/Volumes/work/Android分区存储/Android发布文章/SAF/create_document.png)]

  • onActivityResult中写入内容
REQUEST_CODE_CREATE_FILE -> {
    val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
            Intent.FLAG_GRANT_WRITE_URI_PERMISSION
    contentResolver.takePersistableUriPermission(uri, takeFlags)
    val documentFile = DocumentFile.fromSingleUri(this, uri)
    val outputStream = contentResolver.openOutputStream(uri) ?: return
    val inputStream = this.assets.open("friends.jpg")
    try {
        outputStream.use { outputStream ->
            inputStream.use { inputStream ->
                val byteArray = ByteArray(1024)
                while (true) {
                    val readCount = inputStream.read(byteArray)
                    if (readCount == -1) {
                        break
                    }
                    outputStream.write(byteArray, 0, readCount)
                }
            }
        }
    } catch (e: IOException) {
        Log.e("wfeii", "$e")
    }
}

DocumentFile

对于返回的文件或者目录我们可以使用DocumentFile来操作,DocumentFile提供了三个静态方法,用于获取DocumentFile对象,分别是:

  • //根据File获取DocumentFile
    public static DocumentFile fromFile(@NonNull File file)
    
  • //根据Uri获取目录的DocumentFile
    public static DocumentFile fromTreeUri(@NonNull Context context, @NonNull Uri treeUri)
    
  • //根据Uri获取文件的DocumentFile
    public static DocumentFile fromSingleUri(@NonNull Context context, @NonNull Uri singleUri)
    

DocumentFile提供了很多实用的接口,比如获取文件名等等,方便我们的操作。

引入方式:

  • //androidx
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    
  • //非androidx
    implementation 'com.android.support:support-v4:28.0.0'
    

SAF针对选择文件是很方便的,以前我们使用它的时候,是先获取其对应File的目录再来做出来,而Android11中非公共目录下文件是不能直接操作的,我们可以复制我们自己的目录下,然后再做操作。

参考文档

Android 11 中的存储机制更新

访问应用专属文件

共享存储空间

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

管理存储的所有文件

FileProvider的使用

代码地址:https://github.com/wfeii/Android11

限于个人水平,有错误请指出,大家共同学习进步!

扫码关注公众号,查看更多内容。
Android11(30)/Android10(29)分区存储-存储访问框架(SAF)

本文地址:https://blog.csdn.net/wfeii/article/details/108698730