Android10 分区存储的适配规则

 更新时间:2021年05月13日 08:41:27   作者:飞曼巴  
Android设备 在Sdk29己以上推出了分区存储,类似iOS沙箱。应用App 目标版本号为29或以上则需要适配分区存储,本文将具体的讲解适配规则

存储权限

Android Q 仍然使用 READ_EXTRNAL_STORAGE 和 WRITE_EXTRNAL_STORAGE 作为存储相关运行时权限 但现在即使

获取了这些权限,访问外部存储也受到了限制,只能访问自身目录下的文件和公共体内的文件

内部存储 外部存储

内部存储 外部存储 备注
英文名称 Internal storage External storage
版本变更 不变 4.4之前,外部存储仅仅代表SD卡之类的移动存储设备,4.4之后包括内置的外部存储和SD卡(部分手机没有提供SD卡的卡槽,就只有内置的外部存储)
查看方法 用模拟器+adb shell 进入 或者是Android Studio Devices File Explorer 一般的文档管理App 都能看 用 su root 命令给模拟器加权限
组成成分 System/:存放系用数据 data/: 存放应用相关数据 vendor/:用于存放厂商客制化的数据等 私有存储区:android/ 文件夹下,是应用的私有存储区域 公共存储区域:Movie、Download、 DCIM、 Picture、Documents、Ringtones、Music、 Alarms
存储内容 db share preference files cache 等 开发者自己需要存储的数据 如视频文件、音频文件、或者一些表格 日志文件 内部存储小而且宝贵我们基本上不要操作它,需要存储的都存储在外部存储
获取路径方法 Environment.getDataDirectory() Context.getFileDir() Environment.getExternalStorageDirectory() (traget>=30,已废弃) Context.getExternalFilesDir() 基本上Context的方法获取的都是应用的私有存储路径 E nvironment的方法获取的都是根目录
应用卸载时 私有路径下的文件全部删除 即:data/user/0/packageName/ 私有路径下的文件全部删除 即:android/data/packageName/ 公共存储区域不变动

适配

  • 获取外部存储 文件夹
// 如果当前目录下没有 fileDirName 文件夹会自动创建
val file:File = context.getExternalFileDir("fileDirName") // fileDirName 文件夹名称
// /storage/emulated/0/Android/data/packageName/files/fileDirName
  • 创建外部存储 文件
  val appFileDirName = applicationContext.getExternalFilesDir("fileDirName")?.absolutePath
  val newFile = File(appFileDirName, "temp.txt")
  val fileWriter = FileWriter(newFile)
  fileWriter.write("test information")
  fileWriter.flush()
  fileWriter.close()
  • 创建外部存储公共目录下的文件路径
    /**
     * @param fileName 文件名称
     * @param relativePath 包含某个媒体下的子路径
     */
    fun insertFileIntroMediaStore(
        context: Context,
        fileName: String,
        relativePath: String
    ): Uri? {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            return null
        }
        val contentResolver = context.contentResolver
        val values = ContentValues()
        values.put(MediaStore.Downloads.DISPLAY_NAME, fileName)
        values.put(MediaStore.Downloads.MIME_TYPE, "text/plain")
        values.put(MediaStore.Downloads.RELATIVE_PATH, relativePath)
      	//验证存储空间的可用性 
      	//由于外部存储空间位于用户可能能够移除的物理卷上,因此在尝试从外部存储空间读取应用专
      	//属数据或将应用专属数据写入外部存储空间之前,请验证该卷是否可访问。
      	//您可以通过调用 Environment.getExternalStorageState() 查询该卷的状态。如果返回的状态为 MEDIA_MOUNTED,那么您就可以在外部存储空间中读取和写入应用专属文件。如果返回的状态为 MEDIA_MOUNTED_READ_ONLY,您只能读取这些文件。
        val externalStorageState = Environment.getExternalStorageState()
        return if (externalStorageState.equals(Environment.MEDIA_MOUNTED)) {
            contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values)
        } else {
            contentResolver.insert(MediaStore.Downloads.INTERNAL_CONTENT_URI, values)
        }
    }

    /**
     * @param context 上下文
     * @param insertUri 存储Uri
     * @param inputStream 文件输出流
     */
    fun saveFile(context: Context, insertUri: Uri?, inputStream: InputStream?) {
        insertUri ?: return
        inputStream ?: return
        val resolver = context.contentResolver
        val out = resolver.openOutputStream(insertUri)
        var read: Int
        val buffer = ByteArray(1024)
        while (inputStream.read(buffer).also { read = it } != -1) {
            out?.write(buffer)
        }
        inputStream.close()
        out?.flush()
        out?.close()
    }

    /**
     * @param context 上下文
     * @param insertUri 存储Uri
     * @param sourceFile 资源文件
     */
    fun saveFile(context: Context, insertUri: Uri?, sourceFile: File?) {
        insertUri ?: return
        sourceFile ?: return
        val inputStream = FileInputStream(sourceFile)
        val resolver = context.contentResolver
        val out = resolver.openOutputStream(insertUri)
        var read: Int
        val buffer = ByteArray(1024)
        while (inputStream.read(buffer).also { read = it } != -1) {
            out?.write(buffer)
        }
        inputStream.close()
        out?.flush()
        out?.close()
    }
  • 读取外部存储 公共目录文件
    /**
     * 获取文件输出流 by uri
     * @param context 上下文
     * @param uri 文件路径
     */
    fun getInputStreamByUri(context: Context, uri: Uri?): InputStream? {
        uri ?: return null
        val openFileDescriptor = context.contentResolver.openFileDescriptor(uri, "r")
        return FileInputStream(openFileDescriptor?.fileDescriptor)
    }

以上就是Android10 分区存储的使用总结的详细内容,更多关于Android10 分区存储的使用的资料请关注脚本之家其它相关文章!

相关文章

  • 简单实现android短信发送器

    简单实现android短信发送器

    这篇文章主要为大家详细介绍了如何简单实现android短信发送器 ,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • 利用MVC编写广告条轮播效果

    利用MVC编写广告条轮播效果

    这篇文章主要为大家详细介绍了利用MVC编写广告条轮播效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • Android串口操作方法实例

    Android串口操作方法实例

    这篇文章主要介绍了Android串口操作方法实例,本文共分5个步骤讲解了Android串口操作方法,并给出代码实例,需要的朋友可以参考下
    2015-04-04
  • Android实现短信发送功能

    Android实现短信发送功能

    这篇文章主要介绍了Android实现短信发送功能,对Android实现短信发送的每一步都进行了详细的介绍,感兴趣的小伙伴们可以参考一下
    2015-12-12
  • Android富文本实现的几种方式汇总

    Android富文本实现的几种方式汇总

    由于项目中需要使用到富文本显示和编辑,索性整理下,这篇文章主要给大家介绍了关于Android富文本实现的几种方式,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • android百度地图之公交线路详情搜索

    android百度地图之公交线路详情搜索

    本篇文章介绍了android百度地图之公交线路详情搜索,实现了百度搜索公交详情具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2016-10-10
  • Java4Android开发教程(三)java基本概念

    Java4Android开发教程(三)java基本概念

    本文介绍了Java4Android的基本概念,都是开发必备的基础知识,希望能对大家有所帮助
    2014-10-10
  • Kotlin入门学习教程之可见性修饰符

    Kotlin入门学习教程之可见性修饰符

    在Kotlin中,不管是类、接口、构造函数、函数、属性及其设置器都具有可见性修饰符,下面这篇文章主要给大家介绍了关于Kotlin入门学习教程之可见性修饰符的相关资料,需要的朋友可以参考下
    2021-11-11
  • Android中使用Post请求的方法

    Android中使用Post请求的方法

    这篇文章主要介绍了Android中使用Post请求的方法,实例分析了Android中使用post请求的原理与具体实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • Android实现计时器功能

    Android实现计时器功能

    这篇文章主要为大家详细介绍了Android实现计时器功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04

最新评论