温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Android10的分区存储机制是什么

发布时间:2020-07-23 10:53:02 来源:亿速云 阅读:153 作者:小猪 栏目:移动开发

这篇文章主要为大家展示了Android10的分区存储机制是什么,内容简而易懂,希望大家可以学习一下,学习完之后肯定会有收获的,下面让小编带大家一起来看看吧。

1. 简介

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

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

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

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

2. 关于Android10的分区机制

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_STORAGEMediaStore 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 &#63;: 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()
}

以上就是关于Android10的分区存储机制是什么的内容,如果你们有学习到知识或者技能,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI