Android分区存储
1、分区存储概述
分区存储是Android 10开始引进的Android系统存储管理机制,它允许App读取和写入App自身创建的文件而不需要任何存储权限。其中根据存储位置的不同,可以分为内部内部存储和外部存储。内部存储就不用多说了,而外部存储又分为私有空间和公共空间。私有存储空间位置是/sdcard/Android/data/包名,而公共空间则是相册、下载等。对我们开发者影响最大的就是对于公共存储空间的读写了,总结如下:
- 对于9.0及以下的版本,仍然使用READ和WRITE权限,之前怎么做,现在还是怎么做
- 对于10.0,可以在清单文件中加入以下代码变得跟9.0以前一样
<application android:requestLegacyExternalStorage="true" ...> ... </application>
但是不建议,因为这种方式在Android 11已经不行了,反正都要适配
- 对于Android 10和11,读写App自己创建的文件不需要任何存储权限,读取其他应用创建的文件需要READ权限,但是WRITE权限被废弃了,写入其他应用创建的文件需要用户的干预。
Android分区存储机制其实挺好的,让很多软件不能为所欲为,至少提高了“犯罪成本”。就是来得晚了一些,导致我们开发者要各种兼容…
2、读取
以读取相册(DCIM)为例
val uris = ArrayList<Uri>()
contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null,null, "${MediaStore.MediaColumns.DATE_ADDED} desc")?.use {// 这里的it是一个Cursorwhile (it.moveToNext()) {val id = it.getLong(it.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)uris.add(uri)}
}
这个contextResolver就是是Context.getContentResolver(),Actvity是Context子类,所以用kotlin就可以直接简写。
这样就拿到了相册里面的图片的Uri,它是“content://”形式的uri:
content://media/external/images/media/71
这种读取形式在低版本也是可用的,但是需要READ权限。在Android 10和11中,如果有READ权限,则可以读取到所有的图片文件的Uri,否则只能读取到App本身创建的文件Uri。
在拿到Uri后,我们可以通过流的形式读取它:
contentResolver.openInputStream(uri)?.use { // do sth
}
如果是用于展示图片,可以使用Glide等开源框架,它们本身就支持加载Uri。
3、写入
同样以写入相册(DCIM)为例:
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.girl)
val values = ContentValues()
values.put(MediaStore.MediaColumns.DISPLAY_NAME, "test.png")
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // RELATIVE_PATH需要API 29values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
} else {values.put(MediaStore.MediaColumns.DATA, "${Environment.getExternalStorageDirectory().path}/${Environment.DIRECTORY_DCIM}/test.png")
}
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)?.also { uri ->contentResolver.openOutputStream(uri)?.use { os ->bitmap.compress(Bitmap.CompressFormat.PNG, 100, os)}
}
同样地,在低版本写入需要WRITE权限,在10和11上不需要。但是如果这个要修改其他App创建的文件,就需要写成这样
private var uri: Uri? = null // 通过某些操作获取这个uri并赋值
private fun change() {val temp = uri ?: returncontentResolver.openInputStream(temp)?.use { val bitmap = BitmapFactory.decodeStream(it)val values = ContentValues()values.put(MediaStore.MediaColumns.DISPLAY_NAME, "test.png")values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png")if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // RELATIVE_PATH需要API 29values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)} else {values.put(MediaStore.MediaColumns.DATA, "${Environment.getExternalStorageDirectory().path}/${Environment.DIRECTORY_DCIM}/test.png")}try {contentResolver.openOutputStream(temp)?.use { os ->bitmap.compress(Bitmap.CompressFormat.PNG, 80, os)Toast.makeText(this@MainActivity, "OK", Toast.LENGTH_SHORT).show()}} catch (e: Exception) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && e is RecoverableSecurityException) {startIntentSenderForResult(e.userAction.actionIntent.intentSender, 10086, null, 0, 0, 0)} else {throw e}}}
}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if(requestCode == 10086 && resultCode == RESULT_OK) {change()}
}
会弹出这样的弹窗
如果是对多个文件进行写入,在Android 11上可以这样写:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {val request = MediaStore.createWriteRequest(contentResolver, listOf(uri1, uri2))startIntentSenderForResult(request.intentSender, 10086, null, 0, 0, 0)
}
值得一提的是,用户如果卸载了App后再重新安装,即使是卸载前App自身创建的文件也需要相关权限。也就是说卸载重装之后,“同一个App”其实在系统眼里不是同一个App。
3、管理存储的权限
分区存储机制很好地规范了Android App的存储行为,让它们读自己该读的,写自己该写的。但是有的应用天生就需要对SD卡进行全方位的访问,比如各种文件浏览器、垃圾清理软件等等,虽然很多所谓的垃圾清理软件本身就是最该被清理的垃圾…对此,Android 11引入了一个新的权限:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
有了这个权限,就可以跟以前的版本一样随意玩耍了。那么是不是可以直接申请这个权限就可以了呢?机智如我,是可以的,不过应用市场不让上架…所以大部分App是不允许使用这个权限的。如果要申请此权限,需要打开设置界面,让用户手动设置
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
startActivityForResult(intent, 10010)
如果在manifest中添加了requestLegacyExternalStorage属性,还可以加上包名
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
intent.data = Uri.parse("package:$packageName")
startActivityForResult(intent, 10010)
出现的界面长这样
Android分区存储相关推荐
- 【错误记录】Android 分区存储 错误 ( 文件格式不匹配 )
文章目录 一.报错信息 二.解决方案 一.报错信息 Android 分区存储 , 将 图片文件 保存到 Movies 目录下报错 : 2021-05-18 14:31:50.691 1341-5448 ...
- android 分区存储适配总结
android 分区存储适配总结 一.分区存储概念 二.分区适配方案 1. 应用分区存储的文件访问规定 (1).应用专属目录 (2).共享目录文件 2.MediaStore API介绍 3.Stora ...
- 强制开启Android 分区存储 沙盘文件系统
为了测试Android 11下强制分区存储后的应用兼容问题,这里摸索了下目前的打开方式 1. 在AS里下载API 30的 虚拟机 2. 打开虚拟机,进入首页后,执行 adb shell sm set- ...
- Android 分区存储常见问题解答
要在 Google Play 上发布,开发者需要将应用的 目标 API 级别 (targetSdkVersion) 更新到 API 级别 30 (Android 11) 或者更高版本.针对新上架的应用 ...
- 【错误记录】Android 分区存储下的 SD 卡应用专属外部存储空间目录访问 ( 需手动创建应用专属外部存储空间目录 )
文章目录 一.报错信息 二.解决方案 一.报错信息 开发时 , 需要向外置 SD 卡中拷贝一些文件 , 应用读取这些文件 , 进行相关配置 ; 但是 Android 系统 , 并不会主动为应用创建文件 ...
- 【Android 文件管理】分区存储 ( 修改与删除图片文件 )
文章目录 一.分区存储模式下使用 MediaStore 修改图片 二.分区存储模式下使用 MediaStore 删除图片 三.相关文档资料 Android 分区存储系列博客 : [Android 文件 ...
- 【Android 文件管理】分区存储 ( 创建与查询图片文件 )
文章目录 一.分区存储模式下使用 MediaStore 插入图片 二.分区存储模式下使用 MediaStore 查询图片 三.相关文档资料 Android 分区存储系列博客 : [Android 文件 ...
- Android11(30)/Android10(29)分区存储-存储访问框架(SAF)
概述 存储访问框架(SAF)是在Android 4.4(API 级别 19)引入的.借助 SAF,用户可轻松打开文档.图像及其他文件. 存储访问框架包含三部分: 文档提供程序 - 文档提供程序以 Do ...
- 结合Android去水印APP谈谈分区存储
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 前言 方便个人更新微信状态,上周花半天时间编写简单的抖音去水印AP ...
最新文章
- CSS 文字溢出显示省略号
- Java里边什么是值传递和引用传递?两个有什么区别
- Go语言构建json和解析json实例
- Oracle之数据操作__分组统计查询
- Vmware ESX server CPU掩码导致的挂起
- Linux 交换文件已存在解决办法
- 51nod 1126 求递推序列的第N项 思路:递推模拟,求循环节。详细注释
- 重磅:微信小程序开放公测了!
- Excel 使用VBA 使表格的值被修改后填充颜色标注
- Spring面试之bean作用域
- ubuntu 安装sql_在Ubuntu上进行SQL Server安装和故障排除
- 常用位操作技巧(Golang)
- Pikachu实验过程3(XSS的分析)
- mysql lru scan depth_如何解决mysql警告:“ InnoDB:page_cleaner:1000毫秒的预期循环用了XXX毫秒。设置可能不是最佳的”?...
- Leetcode 304.二维区域和检索-矩阵不可变
- 开源中国开源世界高峰论坛如期将至
- SQLServer 2008安装教程
- 【休憩时的练手】—— 制作简易的网易云音乐播放器
- AntennaHome Launch 5G Combo Internal PCB Antenna /5G 全频 PCB天线
- 用简单英语谈生意-介绍篇
热门文章
- js 条码枪扫描_js获取USB扫码枪数据
- 三相六脉冲全控整流的延时角与三相电压测量及锁相环的关系
- Termux中安装anconda
- 智慧电力可视化大屏,赋能虚拟电厂精准减碳
- swift 5.1 Json转换之Codable
- 给 Android 开发者的第一堂课
- PowerShell 和Microsoft Dynamics NAV / Business Central 关联
- SwiftUI 视图切换之自定义modal控制Card卡片效果
- MySQL赋权报错:’the right syntax to use near ‘identified by ‘password‘ with grant option‘
- 基于Java毕业设计校园闲置物品信息管理系统源码+系统+mysql+lw文档+部署软件