AndroidQ of 10 Partition Storage Perfect Adaptation Method
- 2021-11-14 07:02:36
- OfStack
Preface
Recently, the adaptation of AndroidQ has been done. As of today, the adaptation of AndroidQ partition storage has been completed, and there are many pits during the period. At present, most of the posts on the Internet are an overview of the changes. The next few posts are a summary of the actual experience code of partition storage and the experience of filling pits. I hereby record 1 and provide help for everyone.
This article is mainly to AndroidQ (10) partition storage adaptation concrete realization
Key points:Android Q file storage mechanism is modified to sandbox mode APP can only access files in its own directory and public media files For AndroidQ below, still use the old file storage method
It should be noted here that when adapting to AndroidQ, it should be compatible with the system version below Q, and use SDK_VERSION to distinguish
Background
Storage permissions
Android Q still uses READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE as storage-related runtime permissions, but even if these permissions are obtained, access to external storage is limited to files in its own directory and public inner body files.
External storage structure partition
Public catalogues: Downloads, Documents, Pictures, DCIM, Movies, Music, Ringtones, etc
Address:/storage/emulated/0/Downloads (Pictures), etc
Files in public directories will not be deleted following APP uninstall.
APP Private Directory
Address:/storage/emulated/0/Android/data/Package Names/files
The private directory holds the private files of app, which will be deleted with the uninstallation of App.
Adaptation guidance
Adding, deleting, modifying and checking files using ContentResolver in AndroidQ
1. Get (create) folders under your own directory
Get and create. If there is no corresponding folder in the mobile phone, the system will automatically generate it
// Create in its own directory apk Folder
File apkFile = context.getExternalFilesDir("apk");
2. Create files in your own directory
Generate the path to be downloaded, read and write through the input and output stream
String apkFilePath = context.getExternalFilesDir("apk").getAbsolutePath();
File newFile = new File(apkFilePath + File.separator + "temp.apk");
OutputStream os = null;
try {
os = new FileOutputStream(newFile);
if (os != null) {
os.write("file is created".getBytes(StandardCharsets.UTF_8));
os.flush();
}
} catch (IOException e) {
} finally {
try {
if (os != null) {
os.close();
}
} catch (IOException e1) {
}
}
3. Create folders under public directories
Write through MediaStore. insert
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
return null;
}
ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues();
values.put(MediaStore.Downloads.DISPLAY_NAME, fileName);
values.put(MediaStore.Downloads.DESCRIPTION, fileName);
// Set the file type
values.put(MediaStore.Downloads.MIME_TYPE, "application/vnd.android.package-archive");
// Attention MediaStore.Downloads.RELATIVE_PATH Need targetVersion=29,
// Therefore, this method can only be used in Android10 Execute on the mobile phone of
values.put(MediaStore.Downloads.RELATIVE_PATH, "Download" + File.separator + "apk");
Uri external = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
Uri insertUri = resolver.insert(external, values);
return insertUri;
4. Create files under the specified folder in the public directory
Combined with the above code, we mainly create files or folders in the public directory to get the local path uri, and different Uri can be saved to different public directories. Next, you can write to the file by using the input and output stream
Important: file://type access files are not supported in AndroidQ, and can only be accessed through uri
ContentResolver resolver = context.getContentResolver();
Uri insertUri = resolver.insert(external, values);
if(insertUri == null) {
return;
}
String mFilePath = insertUri.toString();
InputStream is = null;
OutputStream os = null;
try {
os = resolver.openOutputStream(insertUri);
if(os == null){
return;
}
int read;
File sourceFile = new File(sourcePath);
if (sourceFile.exists()) { // When the file exists
is = new FileInputStream(sourceFile); // Read the original file
byte[] buffer = new byte[1024];
while ((read = is.read(buffer)) != -1) {
os.write(buffer, 0, read);
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
5. Read files in public directory through MediaStore
ParcelFileDescriptor parcelFileDescriptor = null;
FileDescriptor fileDescriptor = null;
Bitmap tagBitmap = null;
try {
parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
if (parcelFileDescriptor != null && parcelFileDescriptor.getFileDescriptor() != null) {
fileDescriptor = parcelFileDescriptor.getFileDescriptor();
// Conversion uri For bitmap Type
tagBitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (parcelFileDescriptor != null) {
parcelFileDescriptor.close();
}
} catch (IOException e) {
}
}
6. Delete files using MediaStore
context.getContentResolver().delete(fileUri, null, null);
7. Permissions required by APP to access files through MediaStore
header 1 | 无权限 | READ_EXTERNAL |
---|---|---|
Audio | 可读写APP自己创建的文件,但不可直接使用路径访问 | 可以读其他APP创建的媒体类文件,删改操作需要用户授权 |
Image | 可读写APP自己创建的文件,但不可直接使用路径访问 | 可以读其他APP创建的媒体类文件,删改操作需要用户授权 |
File | 可读写APP自己创建的文件,但不可直接使用路径访问 | 不可读写其他APP创建的非媒体类文件 |
Downloads | 可读写APP自己创建的文件,但不可直接使用路径访问 | 不可读写其他APP创建的非媒体类文件 |
Follow-up introduction of AndroidQ storage for specific functions, welcome to pay attention ~