1. 简介

大家应该都有过这样的体会,手机用着用着里面就充斥着各种不懂的文件夹和文件。甚至是连已经删除的软件的文件夹还存在。

为什么会发生的这样的问题呢?

因为Google的缺席,导致Android生态野蛮生长,导致很多开发规范没有完全被落实。
为了解决这样的问题,Google决定重拳出击,提出了分区存储(Scoped Storage)机制,也叫沙盒存储机制。
那么什么是沙盒存储机制呢。
沙盒机制是一种安全机制,用于防止应用读取其他应用的数据。

  1. 每个应用程序都有自己的存储空间。
  2. 应用程序不能翻过自己的目录,去访问公共目录。
  3. 应用程序请求的数据都要通过权限检测,不符合要求不会被放行。

2. 关于Android10的分区机制

以 Android 10(API 级别 29)及更高版本为目标平台的应用在默认情况下被赋予了对外部存储设备的分区访问权限(即分区存储), 对外部存储文件访问方式重新设计,便于用户更好的管理外部存储文件。如果不符合条件的会以兼容模式运行,兼容模式跟以前一样,根据路径可以直接存储文件。

应用只能看到本应用专有的目录(通过 Context.getExternalFilesDir() 访问)以及特定类型的媒体。除非您的应用需要访问存放在应用的专有目录以及 MediaStore 之外的文件,否则最好使用分区存储。
在发布Android10的时候官方明确表态:

2020年,主要平台版本将要求所有应用都使用分区存储,无论应用的目标 SDK 级别是多少。因此,您应该提前确保您的应用能够使用分区存储。为此,请确保针对搭载 Android 10(API 级别 29)及更高版本的设备启用了该行为。
翻译成通俗语言,不管是使用requestLegacyExternalStorage=true的方式以兼容模式运行还是降低targetSDK都无法在接下来2020年的Android(API 29)10更新中被豁免。

所以为了应用的稳定性,应该尽在进行适配。

3. 具体分区存储权限的介绍

默认情况下,对于targetSdkVersion大于等于29的应用,其访问权限范围限定为分区存储。此应用无需请求与存储相关的用户权限,即可以查看外部存储中以下类型的文件:

  1. 应用外部特定目录中的文件(使用getExternalFilesDir()访问)。
  2. 应用自己创建的照片、视频和音频(通过MediaStore访问)。

分区存储将影响在Android10系统首次安装启动、且targetSdkVersion >=29的应用。需要访问和共享外部存储文件的应用会受到影响,需要进行兼容性适配。

影响范围:
在Android 10上运行的应用:
1.targetSdkVersion <= 28,不受影响
2.如果targetSdkVersion >= 29,默认情况应用外部存储可见性将被过滤,应用需要对分区存储进行适配。

还有值得注意的是以下两种情况比较特殊,不会受到分区存储的影响:

如果应用最先安装在Android 10以下的系统,
1) 然后系统通过Fota升级到Android 10
2) 应用通过更新升级到targetSdkVersion >= 29

下面是关于分区存储权限和其他相关项目的表格。

类型 位置 访问应用自己生成的文件 访问其他应用生成的的文件 访问方法 卸载应用是否删除文件
外部存储 Photo/ Video/ Audio/ 无需权限 需要权限READ_EXTERNAL_STORAGE MediaStore Api
外部存储 Downloads 无需权限 无需权限 通过存储访问框架SAF,加载系统文件选择器
外部存储 应用特定的目录 无需权限 无法直接访问 getExternalFilesDir()获取到属于应用自己的文件路径

4. 专有目录存储

应用读取或写入应有专有的目录中的文件时,不需要获取存储权限。
在应用中想要获取当前应用的专有存储目录路径是可以用Context.getExternalFilesDir()的方式获取。

val dirpath = context.getExternalFilesDir("")
val fileString = dirpath   File.separator
val file = File(fileString)
...  // 剩下的步骤是用Java IO或者其他IO库来写入数据

5. 共享媒体集合存储

在共享媒体集合存储中保存媒体文件时,需要根据文件的类型选择MediaStore。

把相关数据放入到ContentValues中,最后把ContentValues插入到ContentResolver中,并获得返回的Uri。

通过Uri过得OutputStream,然后用Okio的IO库,进行文件的存储。

关于Okio的只是以后有机会的话,我们再好好讲一讲。

不要忘了这里需要获取权限。

// 把图片下载到共有媒体集合中,并在相册中显示
// 创建ContentValues, 并加入信息
val values = ContentValues()
values.put(MediaStore.Images.Media.DESCRIPTION, downloadedFile.name)
values.put(MediaStore.Images.Media.DISPLAY_NAME, downloadedFile.name)
values.put(MediaStore.Images.Media.MIME_TYPE, mimeType)
values.put(MediaStore.Images.Media.TITLE, downloadedFile.name)
values.put(
  MediaStore.Images.Media.RELATIVE_PATH,
  "${Environment.DIRECTORY_PICTURES}/${downloadedFile.name}"
)
// 插入到ContentResolver,并返回Uri
val insertUri = context.contentResolver.insert(
  MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
  values
)

if (insertUri != null) {
  // 获取OutputStream
  val outputStream = context.contentResolver.openOutputStream(insertUri)
if (outputStream != null) {
  sink = outputStream.sink().buffer()
} else {
  return@runCatching FileDownloadResult.OthersError
  }
} else {
  return@runCatching FileDownloadResult.OthersError
}

 val responseBody = response.body ?: return@runCatching FileDownloadResult.OthersError

try {
  val contentLength = responseBody.contentLength()
  if (contentLength > FileUtil.getAvailableSize(dirPath)) {
    continuation.resume(FileDownloadResult.StorageError)
  }
  var totalRead: Long = 0
  var lastRead: Long

  do {
    lastRead = responseBody.source().read(sink.buffer(), BUFFER_SIZE)
    if (lastRead == -1L) {
      break
    }
    totalRead  = lastRead
    sink.emitCompleteSegments()
  } while (true)
  sink.writeAll(responseBody.source())
  sink.close()
  responseBody.close()
}

6. 其他

Github: https://github.com/HyejeanMOON/ScopedStorageDemo

到此这篇关于详解Android10的分区存储机制(Scoped Storage)适配教程的文章就介绍到这了,更多相关Android10 分区存储机制内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

详解Android10的分区存储机制(Scoped Storage)适配教程的更多相关文章

  1. Android10开发者常见问题(小结)

    这篇文章主要介绍了Android10开发者常见问题(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. AndroidQ(10)分区存储完美适配方法

    这篇文章主要介绍了AndroidQ(10)分区存储完美适配方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. Android10 客户端事务管理ClientLifecycleManager源码解析

    这篇文章主要介绍了Android10 客户端事务管理ClientLifecycleManager源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. Android10填坑适配指南(实际经验代码)

    这篇文章主要介绍了Android10填坑适配指南(实际经验代码),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  5. Android 10 适配攻略小结

    这篇文章主要介绍了Android 10 适配攻略小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  6. Android10 Binder原理概述深入解析

    这篇文章主要为大家介绍了Android10 Binder原理概述深入解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  7. 详解Android10的分区存储机制(Scoped Storage)适配教程

    这篇文章主要介绍了详解Android10的分区存储机制(Scoped Storage)适配教程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  8. Android10 启动之SystemServer源码分析

    这篇文章主要为大家介绍了Android10 启动之SystemServer源码分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  9. android10 隐藏SystemUI锁屏下的多用户图标的示例代码

    这篇文章主要介绍了android10 隐藏SystemUI锁屏下的多用户图标,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  10. Android10自动连接WiFi问题的解决

    这篇文章主要介绍了Android10自动连接WiFi问题的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部