IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 【android】关于android10-11存储的一些知识 -> 正文阅读

[移动开发]【android】关于android10-11存储的一些知识

数据存储简述

名称作用详细说明
应用专属存储空间存储应用专属的文件专属存储空间可以在内部存储和外部存储为用户开辟专属的目录,可以用来存储其它用户不能访问的文件,可以通过File api访问,应用被卸载后文件同时被删除,访问不需要权限
共享存储存储所有应用共享的数据存储您的应用打算与其他应用共享的文件,包括媒体、文档和其他文件,可以使用MediaStoreapi访问,应用卸载数据仍然存在,访问需要申请存储权限

外部存储空间的使用

使用外部专属存储空间

android4.4-android9的版本之中,应用被分配了外部专属存储空间,这个空间无需权限即可访问,如果应用想访问其它应用的外部专属存储空间(分区存储),那么需要申请存储权限。

android10以上的版本中,应用的外部存储空间成为了应用的私有空间,任何应用不可以访问其它应用的专属存储空间

  1. 特性

外部专属存储空间位于应用的外部存储中,我们可以在不申请权限的情况下访问外部专属存储空间,外部专属存储空间可以在应用卸载后被删除,专属空间目录媒体文件通常不应该被相册等媒体应用收录(也就是说相册中不会展示这个目录下的图片)(我们自定义的图片选择器也不应该扫描这个目录下的图片)

在低于 android10 的版本中,这个目录是对所有应用可见的

  1. 访问方式

获取目录路径:

  • getExternalFilesDir(""):/storage/emulated/0/Android/data/com.ananananzhuo.storage10demo/files

  • getExternalFilesDirs():获取目录下所有文件的列表

  1. 使用 demo
 val file = File(getExternalFilesDir(""),"安安安安安卓.txt")
            val fos = FileOutputStream(file)
            fos.write("公众号:安安安安安卓".toByteArray(Charsets.UTF_8))
            fos.close()

上面的代码中会在外部专属存储目录(/storage/emulated/0/Android/data/com.ananananzhuo.storage10demo/files)下创建一个安安安安安卓.txt的文件,这里我们没有声明和申请任何权限。执行代码后去看文件选择器中的展示如下:

在外部存储中访问非私有目录则必须声明申请权限
下面我们写一个反面案例

  1. 代码
 ItemData(title = "访问外部存储空间",{
            val file = File(Environment.getExternalStorageDirectory().absolutePath)
            val fileAn = File(file,"安安安.txt")
            logEE(file.absolutePath)
            val fos = FileOutputStream(fileAn)
            fos.write("公众号:安安安安安卓".toByteArray(Charsets.UTF_8))
            fos.close()
        })
  1. 运行后崩溃日志
    提示没有权限

将媒体文件存储在外部专属存储目录的媒体文件夹中

将图片存储到图片文件夹中

  1. 代码
val picFile = getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.apply {
                if (!exists()) {
                    mkdirs()
                }
            }
            val file = File(picFile,"pic.jpg")
            FileOutputStream(file).apply {
                write(12)
                flush()
                close()
            }
  1. 结果

成功存储文件

媒体文件夹还有其他选项:

  • Environment.DIRECTORY_MOVIES
  • Environment.DIRECTORY_DOWNLOADS
  • Environment.DIRECTORY_DOCUMENTS
  • Environment.DIRECTORY_SCREENSHOTS

存储媒体的时候我们应该尽量使用 Environment 中的字符串常量获取媒体文件目录

android10 以上版本能否使用 Environment.getExternalStorageDirectory 存取文件

高于android10的版本无法使用getExternalStorageDirectory api操作文件,因为 api 已经被删除,低于android10可以继续使用该 api

那么高于android10的版本我们应该如何访问这部分的文件呢?别急,后续的共享存储会详细说明

  1. 代码

  1. 效果图

android10以上版本如何获取sd卡中普通目录的图片

我们可以通过SAF在android11以上版本获取普通目录图片(即非专属目录,非共享目录的图片)

本例中的方法不适用于android10以下系统版本(强行使用会崩溃

  1. 代码
 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_directory_scan11)
        findViewById<Button>(R.id.btn_secletdirectory).setOnClickListener {
            val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
            intent.addCategory(Intent.CATEGORY_OPENABLE)
            intent.type = "image/jpeg"
            startActivityForResult(intent, 100)//跳转系统浏览器
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        data?.data?.let {
            iv.setImageURI(it)//通过url处理图片
        }
    }
  1. 效果

内部存储

使用 openFileOutput 和 openFileInput 操作内部存储

将一个文件存储到内部存储的 files 目录下

  1. 代码
openFileOutput("安安安安卓openfileoutput.txt", MODE_PRIVATE).apply {
    write("openFileOutput方法输入流".toByteArray(Charsets.UTF_8))
    flush()
    close()
}

  1. 执行后文件查看

openFileInput 方法和 openFileOutput 一样的使用方式

fileList 获取内部存储全部文件路径

  1. 代码
ItemData(title = "获取目录中所有文件路径",{
            fileList().forEach {
                logEE("文件路径:$it")
            }
        })
  1. 输出日志
E/安安安安卓: 文件路径:安安安安卓openfileoutput.txt

getCacheDir 获取内部存储缓存文件

内部存储缓存中的文件可能会在应用被卸载后被删除,也可能在未卸载前被删除(内部存储空间不足的情况)。所以我们使用内部存储空间缓存文件的时候需要先判断文件是否存在

context.getCacheDir()

共享存储空间(android10 以上版本)

媒体

android10以上将媒体文件文件按类型保存在公共目录上,可以使用 MediaStore 访问媒体文件

以下表格列举所有共享媒体文件类型

媒体类型位置备注
图片存储在 Pictures 和 DICM 目录中,系统将这些文件存放在 MediaStore.Images 中
视频存储 DICM、Movies、Pictures 目录中,系统将这些文件添加到 MediaStore.VIDEO 表中
音频文件存储在 Alarms、Audiobooks、Music、Notifications、Podcasts、Ringtones 目录中,系统将这些文件添加到 MediaStore.Audio 表中
下载文件存储在 Download 目录下,系统将这些文件添加到 MediaStore.Download 表中低于 android10 的版本中不可用
文件集合存在于 MediaStore.Files 表中如果使用了分区存储,这个集合只会显示本应用创建的照片、视频、音频文件

开启分区存储权限,媒体的处理

如果应用使用分区存储,您需要在应用的清单中声明 ACCESS_MEDIA_LOCATION 权限,然后在运行时申请此权限。申请方法后面会讲

编写一个相册

  1. 首先需要获取共享存储中所有的图片地址,代码如下
 private fun getGallaryData(): MutableList<Image> {
        val cursor = contentResolver.query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            null, null, null, "${MediaStore.Images.Media.DISPLAY_NAME} ASC"
        )
        val tempdatas = mutableListOf<Image>()
        cursor?.use {
            val idColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
            val nameColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)
            while (it.moveToNext()) {
                val id = it.getLong(idColumn)
                val contentUrl =
                    ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
                val name = it.getString(nameColumn)
                val image = Image(contentUrl, "")
                tempdatas.add(image)
                logEE("文件名:${contentUrl.path}")
            }
            it.close()
        }
        return tempdatas
    }
  1. 在协程中获取图片 uri,并展示到适配器上
private fun initData() {
        lifecycleScope.launch(Dispatchers.IO) {
            datas.addAll(getGallaryData())
            withContext(Dispatchers.Main) {
                recycle.adapter?.notifyDataSetChanged()
            }
        }
    }
  1. 效果

相册_1.gif

关于android11版本MANAGE_EXTERNAL_STORAGE权限

android10的版本是不能访问所有文件的,可能google也意识到这是不合理的,所以在android11的版本上重新支持了所有文件的访问

android11的系统版本上,如果想扫描应用的所有文件,那么可以声明MANAGE_EXTERNAL_STORAGE权限

MANAGE_EXTERNAL_STORAGE权限需要使用Intent进行权限申请,会跳转到一个系统页面确认权限

需要说明的是:这种方式可以访问共享存储中的文件,但是不可以访问专属存储目录中的文件(Android/data)

如下方法可以判断是否拥有MANAGE_EXTERNAL_STORAGE权限

Environment.isExternalStorageManager()

声明权限方式如下:

  1. manifest中声明权限
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
  1. 申请权限代码
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    startActivity(Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION))
}
  1. 实现效果

其它

权限方面

  • 使用使用共享存储空间访问其它应用创建的应用需要申请存储权限,自己应用本次安装创建的文件不需要申请权限。

  • 如果应用target版本大于 9,那么我们仅应该在<=9 的版本中进行权限申请,可以通过如下配置设置:

maxSdkVersion

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                 android:maxSdkVersion="28" />
  • 如果应用使用了存储兼容功能,那么仍然需要访问存储权限

存储兼容指的就是我们准备升级android10但是暂时不想使用分区存储

开启使用存储兼容只需要在 manifest 中 application 标签声明如下配置即可:

android:requestLegacyExternalStorage="true"

切换媒体文件待处理状态

如果应用操作可能非常耗时(例如写入文件),那么在我们操作文件期间应该避免让其他应用有处理文件的机会。我们可以通过将 ContentValue.put(MediaStore.Audio.Media.IS_PENDING, 1) 标记的值设为 1 来获取此独占访问权限。这样就只有我们的的应用可以操作该文件,直到我们的应用将 IS_PENDING 的值改回 0。

照片中的位置信息

相册中的照片可能会包含敏感信息,例如位置信息,这个信息默认是不允许用户进行查看的,如果想查看需要申请 ACCESS_MEDIA_LOCATION权限

关注公众号学习更多知识

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-02 10:55:55  更:2021-08-02 10:56:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 5:43:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码