App在使用存储功能时会遇到的问题,谨以拙笔 助后至者
targetsdk = 29 (安卓10)
可以在清单文件中 application 标签加上android:requestLegacyExternalStorage=“true”
禁用分区存储,就可以正常使用老存储功能了
targetsdk ≥ 30 (安卓11+)
此时禁用分区存储 也没啥用了,强制开启分区存储
适配
访问应用专属目录(应用内部存储):
- 应用专属目录位于/data/data/包名/下,可以直接访问。
File file = new File(getFilesDir(),"/test");
if (!file.exists())
file.mkdir();
// getFilesDir() -> /data/user/0/应用包名/files
// 创建后 -> /data/user/0/应用包名/files/test
关于getFilesDir() 获取目录是/data/user/0/... 而实际目录是 /data/data/...疑问
在Android 11及更高版本中,使用getFilesDir()方法获取的路径是/data/user/0/packageName,而不是之前的/data/data/packageName。
这是由于Android 11引入了应用沙盒隔离机制的一部分,称为Scoped Storage(作用域存储)。Scoped Storage的目标是提供更加安全和可控的文件访问权限。
在Scoped Storage中,每个应用都有一个私有的存储空间,只能通过应用自身的API进行访问。getFilesDir()方法返回的路径/data/user/0/packageName是一个应用的私有目录,在此目录下创建的文件只能由应用本身访问。
实际上,在/data/user/0/packageName目录下创建的文件仍然存在于/data/data/packageName目录中,但是直接访问/data/data/packageName目录的权限被限制,只有通过应用的API或者特定的访问权限才能进行访问。
这样的变化是为了增强应用数据的隐私和安全性,避免应用之间的数据冲突和滥用。
外部存储:
File file = new File(getExternalFilesDir(null),"/test");
if (!file.exists())
file.mkdir();
// getExternalFilesDir(null) -> /storage/emulated/0/Android/data/应用包名/files
//创建后 -> /storage/emulated/0/Android/data/应用包名/files/test
缓存文件:
File externalCacheFile = new File(context.getExternalCacheDir(), filename);
getExternalCacheDir()
// -> /storage/emulated/0/Android/data/应用包名/cache
//删除缓存文件
externalCacheFile.delete();
媒体文件:
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), albumName);
getExternalFilesDir(Environment.DIRECTORY_PICTURES)
// -> /storage/emulated/0/Android/data/应用包名/files/Pictures
谷歌规定 务必使用 DIRECTORY_PICTURES 等 API 常量提供的目录名称。这些目录名称可确保系统正确处理文件如果没有适合您文件的预定义子目录名称,您可以改为将 null 传递到 getExternalFilesDir()
获取共享的存储目录路径:
Environment.getExternalStoragePublicDirectory()
如获取照片目录路径可以使用
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
查询可用内存:
StorageManager storageManager =
getApplicationContext().getSystemService(StorageManager.class);
UUID appSpecificInternalDirUuid = null;
try {
appSpecificInternalDirUuid = storageManager.getUuidForPath(getFilesDir());
long availableBytes =
storageManager.getAllocatableBytes(appSpecificInternalDirUuid);
Log.i(TAG,"可用空间:"+(availableBytes / (1024 * 1024))+" M");
} catch (IOException e) {
e.printStackTrace();
}
//打印 -> 可用空间:85631 M
关于共享存储空间
- 安卓11引入了一种通过特殊的 SAF(Storage Access Framework)API 访问外部存储的方式,称为共享存储空间(Shared Storage Space)。通过该 API,应用可以允许用户选择访问外部存储的特定文件或目录,并拥有对它们的读写权限。
- 使用共享存储空间,应用可以在用户选择的文件或目录中进行读写操作,而无需直接访问文件路径。
相关细节详见官方:访问应用专属文件 | Android 开发者 | Android Developers (google.cn)