One-partition storage overview
Before Android 10, Android’s file storage phenomenon was like a trash can. Once an app has access to the storage space
WRITE_EXTERNAL_STORAGE
, it can create files arbitrarily, which is difficult to manage. The user experience is also very poor. When you open the file manager, you will find that it is impossible to find a specific file.
1.1 Principles of Partition Storage
In order to better manage your files and reduce confusion, and strengthen privacy protection, Android Q began to introduce a partitioned storage mechanism. The external storage space has been redesigned and divided by application private and public sharing. Applications can only access their own private space, or access shared resource directories through MediaStore API and Storage Access Framework .
Partition storage mainly follows three major principles to redesign file storage:
-
Record the source of the file: The system will record which application the file was created by, and the application can read and write the file created by itself without permission;
The MediaStore database adds a
owner_package_name
field to record which application the file belongs to. After the application is uninstalled, theowner_package_name
field will be blank. That is to say, after uninstalling and reinstalling, the previously created file is no longer created by the application and requires relevant storage permissions to read and write again. -
Application data protection: access restrictions on external storage space, applications can only access their own private space or shared space , even if they have access to read and write permissions, they cannot access the private space of other applications;
-
User data protection: When users download some files, such as email attachments with sensitive information, these files should not be visible to other applications. Added access restrictions for pdf, office, doc and other files. Even if users apply for storage permissions, they cannot access pdf, office, doc and other files created by other applications through MediaStore. They need to be selected by the user through the Storage Access Framework framework. access permission
The newer version of the Android system, it is more dependent on the use of file instead of the position to determine the application access to the file
1.2 Compatibility and judgment about storage methods
- When targetSdk <= 28, the application uses the traditional storage method;
- When targetSdk <= 29, you can
android:requestLegacyExternalStorage="true"
turn off the partition storage function by adding it to the application tag of the application manifest , and continue to use the traditional access method. - When targetSdk>>=30, Android will enforce partition storage and cannot be closed.
- You can
Environment.isExternalStorageLegacy()
judge the running mode of the application storage, true means running in a traditional compatible way, false means running in partitioned storage
Note : When the value of the requestLegacyExternalStorage attribute is modified, the old APK must be uninstalled before the reinstallation will take effect
Second, the impact of storage space
Android provides two types of physical storage locations : internal storage space and external storage space . On most devices, the internal storage space is smaller than the external storage space. However, the internal storage space on all devices is always available, so it is more reliable when storing data that applications depend on.
Removable volumes (such as SD cards) are external storage spaces in the file system. The space is large, and current smart phones are basically equipped, but for compatibility, you can also check whether the space is available when using the relevant API.Environment.getExternalStorageState()
// 是否可读写
fun isExternalStorageWritable(): Boolean {
return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
}
// 是否可读
fun isExternalStorageReadable(): Boolean {
return Environment.getExternalStorageState() in
setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY)
}
Before writing to storage, you need to know how much space is available on the device, and an exception will be thrown if it is not enough. However, the memory of smart devices is relatively large now. For this part, you can refer to Google to query the available space.
2.1 Internal storage space
When you open the Device File Explorer of Android studio, you can see the internal space directory of the application: /data/data/package name/
The internal storage space itself is designed to protect application privacy. This part is unchanged . Applications do not need any system permissions to read and write files in these directories. Other apps cannot access files stored in the internal storage space.
The internal storage space provides a directory for the application. One directory is designed for the persistent files of the application, and the other directory contains the cached files of the application. The internal storage space is exclusive to the application, and File
related APIs can be used normally , so you can play freely as long as you get the path:
-
Persistent file root directory File:,
context.filesDir()
/data/data/package name/files/ -
Cache file root directory File::
context.cacheDir()
, /data/data/package name/cache/
Android also provides some simple APIs to create and delete files:
context.openFileOutput(filename, Context.MODE_PRIVATE)
、context.openFileInput(filename)
、context.fileList()
、context.getDir(dirName, Context.MODE_PRIVATE)
、context.delefteFile(fileName)
Note: After uninstalling the app, the system will automatically remove these directories to free up space! !
2.2 External storage space
/storage/emulated/0/Android/data/包名
The partition storage feature of Android 10 redesigns the external storage space of the Android system. The external storage is divided into two parts: application private directory and shared directory:
- Application private directory: store application private data, external storage application private directory corresponds to Android/data/package name
- Shared directory: Store files accessible to other applications, including media files, document files, and other files, corresponding to directories such as DCIM, Pictures, Alarms, Music, Notifications, Podcasts, Ringtones, Movies, Download, etc.
2.2.1 Application private space
The same as before, access to the private space of the application under its own external storage does not require any permissions. Like the internals, there is also a directory designed for persistent files of the application, and another directory contains the cached files of the application. File
Related APIs can also be used normally , so you can play freely as long as you get the path.
The difference that needs to be noted is: After the partition storage feature is turned on, the application can only access its own private space, even if it has the storage permission, it cannot access the private space of other applications.
In addition, the difference with the internal space is that the external storage space may be removed or there may be more than one, so what is returned is an array, and the first element in the returned array is regarded as the main external storage volume. Unless the volume is full or unavailable, use the volume.
- Persistent files:
getExternalFilesDirs(@NonNull Context context, @Nullable String type)
According to the file type, type can be transferred to the sub-directory constants predefined by the system , such as picturesEnvironment.DIRECTORY_PICTURES
, which will be returned at this time/storage/emulated/0/Android/data/包名/files/Pictures
. Or pass null and return directly/storage/emulated/0/Android/data/包名/files
- Cache
ContextCompat.getExternalCacheDirs(context)
documents: ,/storage/emulated/0/Android/data/包名/cache
Note: After uninstalling the app, the system will automatically remove these directories to free up space! !
The impact of three shared storage space
If user data is or should be accessible to other apps, and it can be saved even after the user uninstalls the app, use shared storage.
Shared file types, including media files, document files and other files, corresponding to the device DCIM, Pictures, Alarms, Music, Notifications, Podcasts, Ringtones, Movies, Download and other directories. Android respectively provides APIs for obtaining Uri of this type of sharable data file:
- Media content :
MediaStore
This content can be accessed using API - Documents and other files : The system has a special directory to contain other file types, such as PDF documents and books in EPUB format. Applications can use to
Storage Access Framework
access these files.
For shared files,. In the past, it was possible to data column
obtain the path and then use the File API to operate, but now it will return failure. After the partition storage feature is enabled, the application can only request the corresponding file from the system through the api provided by the system Uri
, and read and write the file through Uri
generation FileDescriptor
and InputStream
other methods: (In short, for the addition, deletion, and modification of shared files, the main The problem is the acquisition of Uri )
Note: Android 11 also allows access via path, and the system will automatically redirect to Uri.
val resolver = applicationContext.contentResolver
//读
resolver.openFileDescriptor(content-uri, "r")?.use { pfd ->
val inputStream = FileInputStream(pfd.fileDescriptor)
}
resolver.openInputStream(content-uri).use { stream ->
}
//写
resolver.openFileDescriptor(content-uri, "w")?.use { pfd ->
val outputStream = FileOutputStream(pfd.fileDescriptor)
}
resolver.openOutputStream(content-uri).use { stream ->
}
//图片bitmap
BitmapFactory.decodeFileDescriptor(pfd.fileDescriptor)
3.1 MediaStore API
For the addition, deletion, and modification of MediaStrore API, please refer to the official Google guide . The corresponding uri is mainly obtained through contentResolver, which will not be introduced here. Image Source
3.1.1 Overview of MediaStore
The Android system will automatically scan the external storage space and add media files according to their types to the pre-defined collections of Images, Videos, Audio files, and Downloaded files . Android Q accesses corresponding shared directory file resources through MediaStore.Images, MediaStore.Video, MediaStore.Audio, MediaStore.Downloads. The directories corresponding to the predefined collections are shown in the following table:
media type | Hate | Create directory by default | Allow directory creation |
---|---|---|---|
Image | content://media/external/images/media | Pictures | DCIM,Pictures |
Audio | content://media/external/audio/media | Music | Alarms,Music,Notifications,Podcasts,Ringtones |
Video | content://media/external/video/media | Movies | DCIM,Movies |
Download | content://media/external/downloads | Download | Download |
Note: It MediaStore.Downloads.EXTERNAL_CONTENT_URI
is a new API for Android 10 version, used to create and access non-media files
3.1.1 Changes in MediaStore
- MediaStore API creates files in the specified directory of the shared directory or accesses applications to create files by themselves, without applying for storage permissions;
- MediaStore API accesses media files (pictures, audios, videos) created in shared directories by other applications. You need to apply for storage permissions. If you don’t apply for storage permissions, the file Uri cannot be queried through ContentResolver, even if the file Uri is obtained by other means, read or Creating a file will throw an exception;
- The MediaStore API cannot access non-media files (pdf, office, doc, txt, etc.) created by other applications. The only way to access non-media files created by other applications in Android 10 is to use the Storage Access Framework. Document selector provided.
3.1.2 Where are the files created through api stored? How to customize the location?
When MediaStore API
creating a file, the file will be saved to the corresponding type directory by default. For example, when the picture is saved in the Pictures/
directory, you can go up to view the default directory and allowable directory of the table;
You can use MediaStore.xxx.Media.RELATIVE_PATH
the directory or subdirectory you specify to store, such as:, the contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/自定义子目录")
file will be placed Pictures/自定义子目录/
in; or use contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment. DIRECTORY_DCIM)
, put the file DCIM/
in
Note: Each type has a corresponding directory that can be created, otherwise it will return a failure. You can view the table above for specific directories that can be created
3.2 Storage Access Framework
The SAF framework allows users to interact with system selectors to select document providers and specific documents and other files for your application to create, open, or modify. Since users are involved in the selection of files, this mechanism does not require any system permissions.
Application by calling ACTION_CREATE_DOCUMENT
, ACTION_OPEN_DOCUMENT
and ACTION_OPEN_DOCUMENT_TREE
Intent to obtain documents Document provider provides and receives the selected file is returned in onActivityResult interface Uri. In addition, when configuring the intent, you should specify the file name and MIME type, and you can also use EXTRA_INITIAL_URI
intent extra to specify the URI of the file or directory that the file selector should display when it is first loaded as needed .
This part is also unchanged, you can refer to the official guide: Accessing documents and other files from shared storage
3.2.1 Obtaining persistent permissions
For the uri permissions obtained through the SAF framework, you can apply for persistent permissions without having to re-request each time the phone is restarted.
contentResolver.takePersistableUriPermission(
documentUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
Overview of the differences between Android versions of the four storage features
4.1 Other changes: picture location information
Some photos include location information in their metadata so that users can see where the photos were taken. Since this location information is sensitive information, if the app uses partitioned storage, Android 10 will hide this information from the app by default.
If the application needs to access the location information of the photo:
- Request
ACCESS_MEDIA_LOCATION
permission in app manifest - By calling
setRequireOriginal()
, fromMediaStore
acquiring objects exact byte photos, and pictures of the incoming URI
Five updates
5.1 Partition storage "bug" of Android 10
Android 10 deletes a media file through the MediaStore API, but simply removes the index of the MediaStore database, but does not actually delete the physical file on the physical storage, and as long as the phone restarts, the index is added again. issue
This requirement is also relatively rare, but it just happened to be discovered by testing. I checked it online and found that this problem does exist, and Android 11 can be deleted normally. If there is any solution, please point it out! !
5.2 Android 11 storage changes
5.2.1 Allow to continue to use the original file path
The file path can be used again, the system automatically redirects to Uri
5.2.2 Add batch operation
In Android 10, the application must obtain the user's confirmation one by one when requesting to edit or delete each file in the MediaStore. In Android 11, applications can request to modify or delete multiple media files at once.
Mainly through the following new batch operation api
method | Description |
---|---|
MediaStore.createDeleteRequest (resolver, uris) | Batch delete (not put in the recycle bin) |
MediaStore.createFavoriteRequest(resolver, uris) | Batch collection |
MediaStore.createTrashRequest (resolver, uris) | Move to the recycle bin in bulk |
MediaStore.createWriteRequest(resolver, uris) | Get write permissions in batches |
val uris = ...
val pi = MediaStore.createWriteRequest(contentResolver,
uris)
startIntentSenderForResult(pi.intentSender, REQUEST_CODE, null, 0, 0, 0)
//相应
override fun onActivityResult(xxx) {
when (requestCode) {
REQUEST_CODE ->
if (resultCode == Activity.RESULT_OK) {
//获得权限,继续操作
} else {
// 用户拒绝了权限授予
}
}
}
Recommended learning video
The secret of Android R partition storage
If you want to learn more about Android-related knowledge points, you can click into my [GitHub] project, which records many Android knowledge points.
Android fans technical exchange and learning group