The previous article Android Pick Multiple Image From Gallery Example has told us how to browse an image gallery to select and show images use Intent.ACTION_GET_CONTENT intent. In that example, we save all user-selected images android file path URI in a list. Then we display those images one by one.
1. How To Select Android Documents By File Type Extension.
- Besides image type files, the Intent.ACTION_GET_CONTENT intent can be used to pick up any android documents with any file type extension.
- What you need to do is just invoke the Intent.ACTION_GET_CONTENT object’s setType method and pass the file type extension string to it.
- For example, to select an android file of any document type, just pass “*/*” to the intent object’s setType method like below.
openAlbumIntent.setType("*/*"); or openAlbumIntent.setType("image/*"); or openAlbumIntent.setType("video/*");
- Please note, you must use the above setType method to set at least one file type extension, otherwise, it will throw below exception.
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.GET_CONTENT }
2. How To Get The Real File Path From Android URI.
- At some time, only save the image URI in the android app is not enough, because the image URI may be changed, or the image URI is not changed but its related image may be removed.
- In this case, we need to save the URI-related images in the android app folder. Then we can use it later such as display it or upload it to a web server, this can improve the Android app performance.
- To achieve the above goal, we need to get the image URI-related file’s real android file path, then we can use this local android file path to read the image and save a copy of the image to our app folder.
- Because from android SDK version 19, to make Android apps secure, android does not allow one Android app to access other app-created files from the android storage system directly.
- If your Android app wants to access other app-created files, you should get the file from its ContentProvider with a content URI.
- The ContentProvider URI is not a real android file path URI ( such as file:///storage/41B7-12F1/DCIM/Camera/IMG_20180211_095139.jpg), it is a content provider style URI ( such as content://media/external/images/media/1302716 ).
- So we should parse the content provider style URI to the real android file local path by query-related content provider ( image provider, audio provider, video provider, and document provider ).
- The below source code will show you how to get an android file real local storage path from it’s content provider URI.
/* This method can parse out the real local file path from a file URI. */ private String getUriRealPath(Context ctx, Uri uri) { String ret = ""; if( isAboveKitKat() ) { // Android sdk version number bigger than 19. ret = getUriRealPathAboveKitkat(ctx, uri); }else { // Android sdk version number smaller than 19. ret = getImageRealPath(getContentResolver(), uri, null); } return ret; } /* This method will parse out the real local file path from the file content URI. The method is only applied to the android SDK version number that is bigger than 19. */ private String getUriRealPathAboveKitkat(Context ctx, Uri uri) { String ret = ""; if(ctx != null && uri != null) { if(isContentUri(uri)) { if(isGooglePhotoDoc(uri.getAuthority())) { ret = uri.getLastPathSegment(); }else { ret = getImageRealPath(getContentResolver(), uri, null); } }else if(isFileUri(uri)) { ret = uri.getPath(); }else if(isDocumentUri(ctx, uri)){ // Get uri related document id. String documentId = DocumentsContract.getDocumentId(uri); // Get uri authority. String uriAuthority = uri.getAuthority(); if(isMediaDoc(uriAuthority)) { String idArr[] = documentId.split(":"); if(idArr.length == 2) { // First item is document type. String docType = idArr[0]; // Second item is document real id. String realDocId = idArr[1]; // Get content uri by document type. Uri mediaContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; if("image".equals(docType)) { mediaContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; }else if("video".equals(docType)) { mediaContentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; }else if("audio".equals(docType)) { mediaContentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } // Get where clause with real document id. String whereClause = MediaStore.Images.Media._ID + " = " + realDocId; ret = getImageRealPath(getContentResolver(), mediaContentUri, whereClause); } }else if(isDownloadDoc(uriAuthority)) { // Build download URI. Uri downloadUri = Uri.parse("content://downloads/public_downloads"); // Append download document id at URI end. Uri downloadUriAppendId = ContentUris.withAppendedId(downloadUri, Long.valueOf(documentId)); ret = getImageRealPath(getContentResolver(), downloadUriAppendId, null); }else if(isExternalStoreDoc(uriAuthority)) { String idArr[] = documentId.split(":"); if(idArr.length == 2) { String type = idArr[0]; String realDocId = idArr[1]; if("primary".equalsIgnoreCase(type)) { ret = Environment.getExternalStorageDirectory() + "/" + realDocId; } } } } } return ret; } /* Check whether the current android os version is bigger than KitKat or not. */ private boolean isAboveKitKat() { boolean ret = false; ret = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; return ret; } /* Check whether this uri represent a document or not. */ private boolean isDocumentUri(Context ctx, Uri uri) { boolean ret = false; if(ctx != null && uri != null) { ret = DocumentsContract.isDocumentUri(ctx, uri); } return ret; } /* Check whether this URI is a content URI or not. * content uri like content://media/external/images/media/1302716 * */ private boolean isContentUri(Uri uri) { boolean ret = false; if(uri != null) { String uriSchema = uri.getScheme(); if("content".equalsIgnoreCase(uriSchema)) { ret = true; } } return ret; } /* Check whether this URI is a file URI or not. * file URI like file:///storage/41B7-12F1/DCIM/Camera/IMG_20180211_095139.jpg * */ private boolean isFileUri(Uri uri) { boolean ret = false; if(uri != null) { String uriSchema = uri.getScheme(); if("file".equalsIgnoreCase(uriSchema)) { ret = true; } } return ret; } /* Check whether this document is provided by ExternalStorageProvider. Return true means the file is saved in external storage. */ private boolean isExternalStoreDoc(String uriAuthority) { boolean ret = false; if("com.android.externalstorage.documents".equals(uriAuthority)) { ret = true; } return ret; } /* Check whether this document is provided by DownloadsProvider. return true means this file is a downloaded file. */ private boolean isDownloadDoc(String uriAuthority) { boolean ret = false; if("com.android.providers.downloads.documents".equals(uriAuthority)) { ret = true; } return ret; } /* Check if MediaProvider provides this document, if true means this image is created in the android media app. */ private boolean isMediaDoc(String uriAuthority) { boolean ret = false; if("com.android.providers.media.documents".equals(uriAuthority)) { ret = true; } return ret; } /* Check whether google photos provide this document, if true means this image is created in the google photos app. */ private boolean isGooglePhotoDoc(String uriAuthority) { boolean ret = false; if("com.google.android.apps.photos.content".equals(uriAuthority)) { ret = true; } return ret; } /* Return uri represented document file real local path.*/ private String getImageRealPath(ContentResolver contentResolver, Uri uri, String whereClause) { String ret = ""; // Query the URI with the condition. Cursor cursor = contentResolver.query(uri, null, whereClause, null, null); if(cursor!=null) { boolean moveToFirst = cursor.moveToFirst(); if(moveToFirst) { // Get columns name by URI type. String columnName = MediaStore.Images.Media.DATA; if( uri==MediaStore.Images.Media.EXTERNAL_CONTENT_URI ) { columnName = MediaStore.Images.Media.DATA; }else if( uri==MediaStore.Audio.Media.EXTERNAL_CONTENT_URI ) { columnName = MediaStore.Audio.Media.DATA; }else if( uri==MediaStore.Video.Media.EXTERNAL_CONTENT_URI ) { columnName = MediaStore.Video.Media.DATA; } // Get column index. int imageColumnIndex = cursor.getColumnIndex(columnName); // Get column value which is the uri related file local path. ret = cursor.getString(imageColumnIndex); } } return ret; }
3. Load Selected Image Into Memory Issue.
3.1 Question.
- In my program, I get the selected image Uri object with the code data.getData(); and I can get the Uri related string value content://media/external/images/media/99, but how can I get the image file absolute path, I do not need to copy the image to a local app folder, I just want to load the image into memory. But when I reboot my mobile phone, the memory is also lost, can anyone give me some help? Thanks a lot.
3.2 Answer1.
- The example source code in this article has told you how to get an image file absolute path, you can load the image into memory with the absolute file path.
- If your app runs on an Android SDK version smaller than 19 then you can use the method getImageRealPath(), otherwise, you can use the method getUriRealPathAboveKitkat(), please read the 2 methods carefully.
- To fix your android device reboot issue, you can save the user-selected image absolute file path in a configuration file, and when the device reboots, you can get the user last time browsed image’s absolute file path from the configuration file and then display it. Wish this can give you some help.
4. How To Parse the URI To Get the Full File Path Of A File?
4.1 Question.
- In my code, I use the android.provider.MediaStore to get a music file’s full file path.
- This is ok when I select the file using the music player, but it does not work when I use the Astro file browser to select the music file. How to fix this problem, thanks.
4.2 Answer1.
- If your android SDK version is newer than oreo, then you can use the below method to get the music file’s full file path.
- First, you need to get the media object’s Uri object using it’s getData() method.
- Then create a File object with the above Uri object.
- Call the file object’s getPath() method to get it’s full path.
- And then split the file full path to remove the protocol part.
- Below is the example source code.
// Get the music file Uri object. Uri uriObj = data.getData(); // Get the Uri object's path. String uriPath = uriObj.getPath(); // Create a File object from the above Uri path. File file = new File(uriPath); // Get the full file path string of the file object. String fullFilePath = file.getPath(); // Split the protocol and full file path in the above file path. final String[] split = fullFilePath.split(":"); // Get the object's full file path string. String fullFilePathResult = split[1];
5. How To Get The Real Path By Invoking The Android Uri Object’s getPath() Method.
5.1 Question(2022/05/14).
- My source code will get an image file from an image gallery.
- But when the activity returned, I got a Uri data like content://media/external/images/1.
- And what I want is the real file path like /sdcard/image/1.png
- How can I do that? Thanks a lot.
- Below is the source code.
// Create an intent object. Intent intent = new Intent(); // Set the intent type. intent.setType("image/*"); // The intent will open a file browser. intent.setAction(Intent.ACTION_GET_CONTENT); // Show a file browser to let the user to select file with the file type. startActivityForResult(Intent.createChooser(intent, "Select picture"), resultCode );
5.2 Answer1.
- I think it is not necessary to get the real physical path if you just want to use the file in your app.
- For example, if you just want to show the image in an ImageView object, you can follow the below steps.
- You can first get the image Uri object (call the data.getData() method) and then use the ImageView.setImageURI(uriObject) to show it.
- If you want to read the file content you can use the ContentResolver.openInputStream() method.
- But if you want to get the filename and extension, and then convert the image to a physical file, I think maybe you need to get the file real path, but you can give the file a new name also.
Thank you for sharing this helpful post! I’ve been struggling to get the real file path of an image stored in an Uri in Android, and your solution worked like a charm. I appreciate the clear explanations and code examples. This will save me a lot of time and frustration in my next project.
Thanks for sharing this helpful tutorial! I was struggling to get the file path of a file stored on an Android device using the `Uri` class, but your solution worked like a charm. I have a lot of files on my device that I need to access in my app, and now I can do it easily. Great job!
Thank You VERYYY much !!! it workeddd !! i had no idea how to get path for a database file(.db) .. turns out it’s a “content” file and not a “file” file lol which kinda makes sense ig. but yeah THANK YOU
I was searching for this stuffs since two-three days. Thanks a lot. I almost gave up. Thanks a lot.
Thank you.
But in android emulator (include Android 9.0) …..
Uri downloadUri = Uri.parse(“content://downloads/public_downloads”);
In this part, the issue was happened.
I hope you help me as soon as possible.
Best wishes
You shouldn’t try to get file path from Uri. Or at least you should understand that not all Uris can provide you with a file path!
read this: https://stackoverflow.com/a/49619018/5502121
The code above will crash if your Uri won’t have a ‘_data’ column in the cursor if it’s media.
For example, In my case user draws a picture, and it is saved as a Bitmap in .png file. I create a Uri using FileProvider and this Uri IS a MEDIA but DOESN”T HAVE the ‘_data’ column.
And the last thing: this code is very inefficient – you shouldn’t query with ‘null’ as a projection (the list of columns).
And there is a lot of such cases.
Why do I feel that there is a shorter way to get this done??
Jerry. Your code is wonderful. This helped me a lot with my school project. But how did you learn all this if the info is not in the Android documentation?
Hey, Thank you for the code. It works for most apps but does not work for images shared from WhatsApp. I am trying to catch the images shared from WhatsApp to my app but the uri of the images does not give the real path. When i’m using your code it gives the error:
java.lang.IllegalStateException: Couldn’t read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly
Can you please suggest something to fix it.
Thank you
From the error message, it said the col number is -1 which is not correct, because the minimum col value should be 0.
I think you should set a breakpoint at where the error occurred, and debug into it to fix this error.
Hey I am facing the same problem when trying to open the file shared on whatsapp. Have you found any solution?
Super nice……. 1000/1000
You are my hero, such a mess on documenting this on google’s part
Very helpful, thanks!!!