Android10 分区存储的适配规则

作者:飞曼巴 时间:2022-11-25 12:22:53 

目录
  • 存储权限

  • 内部存储 外部存储

  • 适配

存储权限

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

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

内部存储 外部存储


内部存储外部存储备注
英文名称Internal storageExternal 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)
   }

来源:https://juejin.cn/post/6961192407903780871

标签:Android,分区存储
0
投稿

猜你喜欢

  • Java8 Comparator源码演示及解析

    2023-09-18 10:51:12
  • 解决Intellij IDEA 使用Spring-boot-devTools无效的问题

    2023-09-17 20:49:47
  • C#中控件动态添加事件绑定的时机详解

    2022-05-05 17:40:59
  • IDEA(jetbrain通用)使用教程图解

    2023-04-15 04:05:49
  • Java 比较接口comparable与comparator区别解析

    2022-11-26 20:54:24
  • Java设计模式之工厂模式实现方法详解

    2023-11-26 07:55:51
  • 解决idea 项目编译后没有class文件的问题

    2023-11-04 07:55:06
  • 打印Java程序的线程栈信息方式

    2021-11-02 19:00:28
  • c# 制作gif的四种方法

    2023-03-17 20:01:08
  • C#路径,文件,目录及IO常见操作汇总

    2022-05-03 21:21:13
  • C#从windows剪贴板获取并显示文本内容的方法

    2022-06-03 01:56:47
  • 浅谈为什么要使用mybatis的@param

    2023-07-01 20:12:39
  • 浅谈spring security入门

    2023-02-20 04:48:58
  • Unity实现截图功能

    2022-02-18 11:36:18
  • FastJSON字段智能匹配踩坑的解决

    2022-07-29 19:32:26
  • C#中的委托使用

    2021-08-12 09:36:57
  • C#委托用法详解

    2023-06-04 22:46:43
  • Java项目中获取路径的绝对路径问题和相对路径问题

    2023-07-09 13:25:01
  • java查询mongodb中的objectid示例

    2022-03-06 08:59:21
  • OpenJDK源码调试图文教程

    2022-09-26 01:40:25
  • asp之家 软件编程 m.aspxhome.com