You probably already know that the words on the new android operating systems help to better protect application data and users on external memory. Direct operations via filePath will no longer be available to android developers.
And Google has also created a flag called requestLegacyExternalStorage
on Android 10 to give developers more time to update their apps to be compatible with this new update. However, this flag will be useless on Android 11 (More details can be found at this full HD link ). Failure to get the file path field anymore will cause relatively difficult to handle files on Android such as reading files, uploading files, …
In this article I will suggest you methods to be able to upload files via uri.
Suppose I have api to create users with the necessary Body including “name”, “date_of_birth” with an image file that is the user’s avatar.
1 2 3 4 5 6 7 8 | public interface APIService { @Multipart @POST("add_user") Single<User> addUser(@Part("name") RequestBody name, @Part("date_of_birth") RequestBody dateOfBirth, @Part MultipartBody.Part avatar); |
Choose a photo from the gallery
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public void pickImage(){ Intent intent = new Intent(); intent.setAction(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); startActivityForResult(Intent.createChooser(intent, "Select Picture"), 1); } @Override public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (requestCode == 1 && data != null) { Uri uri = data.getData(); viewmodel.setUriImage(uri); } } } |
Create request body from Uri
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public class FileRequestBody extends RequestBody { private InputStream inputStream; private MediaType type; public UploadFileRequestBody(InputStream inputStream, MediaType type) { this.inputStream = inputStream; this.type = type; } @Override public MediaType contentType() { return type; } @Override public long contentLength() throws IOException { return inputStream.available(); } @Override public void writeTo(@NonNull BufferedSink sink) throws IOException { Source source = null; try { source = Okio.source(inputStream); sink.writeAll(source); } catch (Exception e) { if (source != null) { source.close(); } } } } |
The function takes mediaType of file in class Utils
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class Utils { public static String getContentType(Uri uri) { String type = null; Cursor cursor = <Your Application>.getContentResolver().query(uri, null, null, null, null); try { if (cursor != null) { cursor.moveToFirst(); type = cursor.getString(cursor.getColumnIndex(Media.MIME_TYPE)); cursor.close(); } } catch (Exception e) { e.printStackTrace(); } return type; } } |
Call api add User
1 2 3 4 5 6 7 8 9 10 | public Single<User> addUser(String name, String dateOfbirth, Uri imageUri) { RequestBody nameBody = RequestBody.create(MediaType.parse("text/plain"), name); RequestBody dateOfBirthBody = RequestBody.create(MediaType.parse("text/plain"), dateOfbirth); String contentType = Utils.getContentType(uri) FileRequestBody requestBody = new FileRequestBody(<Your Application>.getContentResolver().openInputStream(imageUri), contentType); MultipartBody.Part imageBody = MultipartBody.Part.createFormData("filename", "<Your file name>", requestBody); return apiService.addUser(nameBody, dateOfBirthBody, imageBody); } |