preface
A cup of tea, a pack of cigarettes, a Bug change a day! One day, when I was immersed in the joy of moving bricks, suddenly received a picture, is like this
WTF! Dry!
adapter
AndroidQ adaptation was just released when the news, but also caused a stir, one of the most important is partition storage, although there are a lot of other changes, of course, that is the icing on the cake, temporary not adaptation will not have any impact, but partition storage is not the same! But fortunately Google left a successful, AndroidQ can temporarily use requestLegacyExternalStorage attributes close partition storage, why say temporarily? Because later this attribute is invalid, for some projects that have passed N more than hands, it is good to run carefully! So someone like me, who’s lazy and a vegetable, might just add it and be done with it. Haha!! Partition storage concept I believe everyone is familiar, here is not much force force! Because the project I am involved in is mainly for the overseas market, so I still have to see the face of Google market! So there’s no hiding this time!
Android R
When I got an email from Google, I took a quick look at the official Google documentation and found that Android R and Q are generally similar in terms of partitioned storage, but there are differences! For example, Android R uses the File API in addition to the MediaStore API. Solution: 10 with requestLegacyExternalStorage Android, Android 11 with the new API. This is a way to save time and effort and I just need to adapt for version R. Of course, the actual situation of each project is different, and the places that need to be adapted are also different. The places that need to be adapted in the author’s project are mainly divided into:
2. Query the third-party application package name (used for system sharing) : <queries> <package android:name=" XXX package name XXX "/> </queries> 3 The project has its own photo gallery feature, which retrieves pictures and videos from your phone via ContentResolver, Query (QUERY_URI, QUERY_URI, Selection, selectionArgs, orderBy) is the main method for adaptation. However, in Android R, The bundle parameter is used to query the bundle. The limit parameter in the Order Derby parameter is also different: public static Bundle createQueryArgsBundle(String selection, String[] selectionArgs, int limitCount, int offset) { Bundle queryArgs = new Bundle(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { queryArgs.putString(ContentResolver.QUERY_ARG_SQL_SELECTION, selection); queryArgs.putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs); queryArgs.putString(ContentResolver.QUERY_ARG_SQL_SORT_ORDER, MediaStore.Files.FileColumns._ID + " DESC"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { queryArgs.putString(ContentResolver.QUERY_ARG_SQL_LIMIT, limitCount + " offset " + offset); } } return queryArgs; } 4. System picture clipping is changed from path to URI 5. Other changes such as location permission change are not mentioned in this project.Copy the code
Actually finish the above work, the Android R adaptation basic no problem, because on Android Q version of the mobile phone requestLegacyExternalStorage attribute, operation is also no problem!
Android Q
If all that said, there would be no Android Q of adaptation, so the problem is out in Google’s statement, Google application market detect requestLegacyExternalStorage every time, and not sure what will be the resulting special effects, such as shelves, email Settings every time warning, This may not be acceptable for the product! So in order to solve these problems, can only be forced to adapt! Android Q adaptation is mainly focused on partition storage, such as dark mode is not necessary adaptation, due to time constraints, temporarily shelved. For this project, the Android Q adaptation or focus on mobile phone image retrieval, such as the ContentResolver MediaStore. The Files. FileColumns. DATA method cannot be used, Can only use MediaStore. Files. FileColumns _ID, again through the id to get the path; Otherwise you retrieve images and videos and there is no cover.
/**
* Android Q
*
* @param id
* @return path
*/
private static String getPathByAndroid_Q(long id) {
return QUERY_URI.buildUpon().appendPath(ValueOf.toString(id)).build().toString();
}
Copy the code
In Android Q, since the images are obtained in the form of files starting with Content :// instead of the previous Android /data app private directory, there is a problem in image cropping, such as in the acquisition of bitmap objects, the previous method is
BitmapFactory.decodeFile(selectImgBean.getImgUrl(), options);
Copy the code
The imgUrl is a traditional file path, such as android/data. In android Q, the imgUrl is a content:// or file:// uri.
try {
InputStream inputStream = App.sApp.getContentResolver().openInputStream(Uri.parse(selectImgBean.getImgUrl()));
BitmapFactory.decodeStream(inputStream, null, options);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
Copy the code
In addition, the path for uploading profile pictures and uploading OSS also needs to be adapted
/** * public static String getRealFilePath(final Context) ** @param URI * @return */ context, final Uri uri) { if (null == uri) { return null; } final String scheme = uri.getScheme(); String data = null; if (scheme == null) data = uri.getPath(); else if (ContentResolver.SCHEME_FILE.equals(scheme)) { data = uri.getPath(); } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) { Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null); if (null ! = cursor) { if (cursor.moveToFirst()) { int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); if (index > -1) { data = cursor.getString(index); } } cursor.close(); } } return data; }Copy the code
Change the URI to the path of the file. Otherwise, an error will be reported when uploading the OSS. Other modifications are when downloading images or files, changing the saved directory from the public directory to the App’s private directory, manipulating images or videos in the public directory via MediaStore. If it is an image, there may also be a need to save the image to the album, also need to make changes, for example:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
String fileName = file.getName();
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
ContentResolver contentResolver = activity.getContentResolver();
Uri uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
if (uri == null) {
ToastManager.showShort(activity, MultiLang.getString("downloadFailed", R.string.downloadFailed));
return;
}
try {
OutputStream out = contentResolver.openOutputStream(uri);
FileInputStream fis = new FileInputStream(file);
FileUtils.copy(fis, out);
fis.close();
out.close();
ToastManager.showShort(activity, MultiLang.getString("downloadSuccess", R.string.downloadSuccess));
} catch (IOException e) {
e.printStackTrace();
}
Copy the code
conclusion
Since there are only so many problems involved in this project, and the time is very short, the overall point is to change where the problems occur, but also to have a general expectation in mind, know where the problems may occur, and make a reasonable schedule. If conditions allow, or early adaptation is better, to avoid this sudden policy to get unprepared!