Get/pick an image from Android's built-in Gallery app programmatically
Solution 1
This is a complete solution. I've just updated this example code with the information provided in the answer below by @mad. Also check the solution below from @Khobaib explaining how to deal with picasa images.
Update
I've just reviewed my original answer and created a simple Android Studio project you can checkout from github and import directly on your system.
https://github.com/hanscappelle/SO-2169649
(note that the multiple file selection still needs work)
Single Picture Selection
With support for images from file explorers thanks to user mad.
public class BrowsePictureActivity extends Activity {
// this is the action code we use in our intent,
// this way we know we're looking at the response from our own action
private static final int SELECT_PICTURE = 1;
private String selectedImagePath;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.Button01)
.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// in onCreate or any event where your want the user to
// select a file
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
}
}
}
/**
* helper to retrieve the path of an image URI
*/
public String getPath(Uri uri) {
// just some safety built in
if( uri == null ) {
// TODO perform some logging or show user feedback
return null;
}
// try to retrieve the image from the media store first
// this will only work for images selected from gallery
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if( cursor != null ){
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path = cursor.getString(column_index);
cursor.close();
return path;
}
// this is our fallback here
return uri.getPath();
}
}
Selecting Multiple Pictures
Since someone requested that information in a comment and it's better to have information gathered.
Set an extra parameter EXTRA_ALLOW_MULTIPLE
on the intent:
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
And in the Result handling check for that parameter:
if (Intent.ACTION_SEND_MULTIPLE.equals(data.getAction()))
&& Intent.hasExtra(Intent.EXTRA_STREAM)) {
// retrieve a collection of selected images
ArrayList<Parcelable> list = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
// iterate over these images
if( list != null ) {
for (Parcelable parcel : list) {
Uri uri = (Uri) parcel;
// TODO handle the images one by one here
}
}
}
Note that this is only supported by API level 18+.
Solution 2
Here is an update to the fine code that hcpl posted. but this works with OI file manager, astro file manager AND the media gallery too (tested). so i guess it will work with every file manager (are there many others than those mentioned?). did some corrections to the code he wrote.
public class BrowsePicture extends Activity {
//YOU CAN EDIT THIS TO WHATEVER YOU WANT
private static final int SELECT_PICTURE = 1;
private String selectedImagePath;
//ADDED
private String filemanagerstring;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((Button) findViewById(R.id.Button01))
.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// in onCreate or any event where your want the user to
// select a file
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
}
});
}
//UPDATED
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
//OI FILE Manager
filemanagerstring = selectedImageUri.getPath();
//MEDIA GALLERY
selectedImagePath = getPath(selectedImageUri);
//DEBUG PURPOSE - you can delete this if you want
if(selectedImagePath!=null)
System.out.println(selectedImagePath);
else System.out.println("selectedImagePath is null");
if(filemanagerstring!=null)
System.out.println(filemanagerstring);
else System.out.println("filemanagerstring is null");
//NOW WE HAVE OUR WANTED STRING
if(selectedImagePath!=null)
System.out.println("selectedImagePath is the right one for you!");
else
System.out.println("filemanagerstring is the right one for you!");
}
}
}
//UPDATED!
public String getPath(Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if(cursor!=null)
{
//HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL
//THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
else return null;
}
Solution 3
hcpl's methods work perfectly pre-KitKat, but not working with the DocumentsProvider API. For that just simply follow the official Android tutorial for documentproviders: https://developer.android.com/guide/topics/providers/document-provider.html -> open a document, Bitmap section.
Simply I used hcpl's code and extended it: if the file with the retrieved path to the image throws exception I call this function:
private Bitmap getBitmapFromUri(Uri uri) throws IOException {
ParcelFileDescriptor parcelFileDescriptor =
getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return image;
}
Tested on Nexus 5.
Solution 4
I went through the solution from @hcpl & @mad. hcpl's solution supports well for local image in the gallery & mad provided a better solution on top of that - it helps to load OI/Astro/Dropbox image as well. But in my app, while working on picasa library that's now integrated in Android Gallery, both solution fail.
I searched & analyzed a bit & eventually have come with a better & elegant solution that overcomes this limitation. Thanks to Dimitar Darazhanski for his blog, that helped me in this case, I modified a bit to make it easier to understand. Here is my solution goes -
public class BrowsePicture extends Activity {
//YOU CAN EDIT THIS TO WHATEVER YOU WANT
private static final int SELECT_PICTURE = 1;
private String selectedImagePath;
//ADDED
private String filemanagerstring;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((Button) findViewById(R.id.Button01))
.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// in onCreate or any event where your want the user to
// select a file
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), SELECT_PICTURE);
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
Uri selectedImageUri = data.getData();
Log.d("URI VAL", "selectedImageUri = " + selectedImageUri.toString());
selectedImagePath = getPath(selectedImageUri);
if(selectedImagePath!=null){
// IF LOCAL IMAGE, NO MATTER IF ITS DIRECTLY FROM GALLERY (EXCEPT PICASSA ALBUM),
// OR OI/ASTRO FILE MANAGER. EVEN DROPBOX IS SUPPORTED BY THIS BECAUSE DROPBOX DOWNLOAD THE IMAGE
// IN THIS FORM - file:///storage/emulated/0/Android/data/com.dropbox.android/...
System.out.println("local image");
}
else{
System.out.println("picasa image!");
loadPicasaImageFromGallery(selectedImageUri);
}
}
}
}
// NEW METHOD FOR PICASA IMAGE LOAD
private void loadPicasaImageFromGallery(final Uri uri) {
String[] projection = { MediaColumns.DATA, MediaColumns.DISPLAY_NAME };
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if(cursor != null) {
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME);
if (columnIndex != -1) {
new Thread(new Runnable() {
// NEW THREAD BECAUSE NETWORK REQUEST WILL BE MADE THAT WILL BE A LONG PROCESS & BLOCK UI
// IF CALLED IN UI THREAD
public void run() {
try {
Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
// THIS IS THE BITMAP IMAGE WE ARE LOOKING FOR.
} catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
}
}
cursor.close();
}
public String getPath(Uri uri) {
String[] projection = { MediaColumns.DATA};
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if(cursor != null) {
//HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL
//THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndexOrThrow(MediaColumns.DATA);
String filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
}
else
return uri.getPath(); // FOR OI/ASTRO/Dropbox etc
}
Check it & let me know if there's some issue with it. I have tested it & it works well in every case.
Hope this will help everyone.
Solution 5
basis with the above code, I reflected the code like below, may be it's more suitable:
public String getPath(Uri uri) {
String selectedImagePath;
//1:MEDIA GALLERY --- query from MediaStore.Images.Media.DATA
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if(cursor != null){
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
selectedImagePath = cursor.getString(column_index);
}else{
selectedImagePath = null;
}
if(selectedImagePath == null){
//2:OI FILE Manager --- call method: uri.getPath()
selectedImagePath = uri.getPath();
}
return selectedImagePath;
}
Related videos on Youtube
Michael Kessler
I am a Software Development company owner and an independent Mobile developer. Mobile development: - iOS: Swift - Android: Kotlin - iOS: Objective-C - Android: Java
Updated on March 08, 2021Comments
-
Michael Kessler about 3 years
I am trying to open an image / picture in the Gallery built-in app from inside my application.
I have a URI of the picture (the picture is located on the SD card).
Do you have any suggestions?
-
Anthony Forloney over 14 yearsI have updated my answer to provide more test code to ensure that you retrieve the results correctly.
-
mad over 13 yearslook at my answer, it is an update to hcpl's code and it works for astro file manager and oi file manager too.
-
Vikas almost 13 yearsSomeone should update question, "Get/pick an image from Android's...". Current question interprets that I have image and I want to show it via default gallery app.
-
Michael Kessler almost 13 years@Vikas, seems that you are right. I don't remember what exactly I have tried to accomplish more than a year ago and why all the answers (including the one that I have selected as a solution) actually answer to a different question...
-
Michael Kessler almost 13 yearsActually, I don't know if it is right to change the question completely. There are 36 people who have added the question to their favorites...
-
Takermania almost 9 yearsThis question has been answered step by step in this tutorial [click to view Tutorial][1] [1]: stackoverflow.com/questions/30506301/…
-
-
Michael Kessler over 14 years@Anthony, thank you for your response. Unfortunately it doesn't work for me. I get the next error:
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.GET_CONTENT typ=file:///sdcard/images/* }
-
Anthony Forloney over 14 yearsYou need to call
startActivityforResult
and supply an activity. That's what I was referring to about deciding on what to next, my bad. -
Michael Kessler over 14 yearsIt still doesn't work... I check that the folder exists and that there is an image file inside the folder. I call
startActivityForResult(intent, 1);
and still get this error... This code is located outside the Activity, but I have a reference to the activity and call thestartActivityForResult
method on that reference - maybe this is the reason? -
Anthony Forloney over 14 yearsNah, shouldnt be the reason, what is
1
that your passing in? TryIMAGE_PICK
-
Michael Kessler over 14 yearsThe second param is just something for me, isn't it? This is just an int that will be passed back to me together with the result. Tried also the
Intent.ACTION_PICK
instead ofIntent.ACTION_GET_CONTENT
. What do you mean byIMAGE_PICK
? There is no such a constant. I also triedintent.setData(Uri.fromFile(new File("/sdcard/image/")));
. I tried all the possible combinations of these and nothing seems to work... -
Anthony Forloney over 14 yearsyeah
IMAGE_PICK
was a personal constant for another person having problems with Android, I thought it was a constant that choose which image picked, but what happens when you tried to useintent.setData(...)
, do you get an error message? or nothing happens? -
Michael Kessler over 14 yearsI get an exception on
startActivityForResult
method call in all the cases (ACTION_GET_CONTENT
,ACTION_PICK
,setType
,setData
), tried to remove the "file://" prefix, tried to remove the "*" posfix, tried to remove both, tried to give the full path to the file - I've tried all the combinations. Notice that it opens the Gallery app when I don't mention the exact folder or file and use thesetType("image/*");
. -
Michael Kessler over 14 yearsDoes it work for you? Have you tried it? If it does then what platform are you working on? I use the Android 1.5
-
Anthony Forloney over 14 yearsI have not tried it, so I couldn't say whether it would work or not and I am using the Android 2.0
-
Rohith Nandakumar over 13 yearsIt doesn't work when I use Astro file manager. Any ideas why?
-
Vikas over 13 yearsHow do I retrieve Bitmap image from OI path?
-
mad over 13 yearslook at the code. at the lines with the comment //NOW WE HAVE OUR WANTED STRING...this is all you need. then use BitmapFactory class to retrieve a bitmap from a path
-
hcpl almost 13 yearsThanks! You have a good point, never tried other file managers :).
-
GeneCode almost 13 yearsHi thanks a lot for this. Im a noobie though, can anyone tell me how to use the selectedImagePath or the other paths and set the image in ImageView?
-
pgsandstrom almost 13 yearsI would also like to close the cursor :)
-
ashughes over 12 yearsCould also change
else return null;
ingetPath(Uri uri)
toreturn uri.getPath();
and get rid of the firstfilemanagerstring = selectedImageUri.getPath();
check. This way you just make one call togetPath(Uri)
and get the path back (no matter if it was the Gallery or a file manager that was used). -
CQM over 12 yearsonActivityResult is never called in my program :( I am using tabhosts and have tried putting the onActivityResult() method in my TabActivity, my TabGroup AND my original view Activity that originally called the gallery
-
Noby over 12 years@hcpl Thank you for answer. Can you please tell me how to get multiple images...?
-
PiyushMishra over 12 years@Michael kessler I just answer a question stackoverflow.com/questions/6074270/… if it help you in anyway.
-
Gabor over 12 yearssmall addition for device compatibility: intent.setType("image/*"); if (android.os.Build.MODEL.startsWith("HTC")) intent.putExtra("folderType", "com.htc.HTCAlbum.ALL_PHOTOS");
-
Dave_P over 12 years@hcpl... what if you wanted to drill down into the gallery to a specified directory programatically. If the app creates a directory that shows in the gallery, can you just take the user directly to that gallery? handling exceptions of course. I wouldnt want to show the user every directory and have them select, I just want to show them the directory that I want them to be in. You can email me if you want [email protected]
-
Mario almost 12 yearsthx a lot. but if i choose gallery as source. it will still show the app choice after i select an image. if i choose the filemanager it works all great
-
gcl1 over 11 yearsI think "selectedImagePath = getPath(selectedImageUri);" should be "selectedImagePath = selectedImageUri.getPath();". Then, it compiled and worked for me.
-
Torben over 11 yearsYou did not understand the question before answering. Also, you did not include any description about what you try to do. Also, your code breaks some well established Java programming standards.
-
Khobaib almost 11 years@hcpl I have provided a solution that supports picasa album's image loading also(picase album is part of Android gallery now). Check my solution.
-
Khobaib almost 11 years@mad I have provided a solution that supports picasa album's image loading also(picase album is part of Android gallery now). Check my solution.
-
hcpl over 10 years@gcl1 the getPath() method is a custom helper, don't forget to add it to your code. It will use a content provider if possible and fall back on the uri.getPath() function if not.
-
hcpl over 10 years@Noby check my updated answer, it has some info on how to select multiple images on API level 18 and higher. Before that you'll have to provide your own media browser or look for an open source library.
-
hcpl over 10 years@Khobaib Thanks for the update. I've added a pointer in my answer.
-
Christopher Masser over 10 yearsGetting a single picture doesn't seem to be working on the newest Android version 4.4 (KitKat) anymore. The _data column from the query returns a null value.
-
Snake over 10 years@Chsristopher Masser, Any suggested alternative for Kitkat?
-
IgorGanapolsky over 10 yearsDoes one need to know the uri of the image here? What if I just want to pick an arbitrary image from the gallery?
-
IgorGanapolsky over 10 years@hcpl You didn't mean 'Intent.hasExtra', you meant 'data.hasExtra' - assuming data is your Intent parameter in onActivityResult().
-
bugraoral over 10 yearsIntent which you will receive from the gallery will provide you the url
-
abbath over 10 yearsThis code is working perfectly preKitkat, but from then there are document providers. In my answer I write about what to do in kitkat.
-
Johan about 10 yearsI get the onActivityResult before I select an image. When I select an image, I get no onActivityResult at all. Testing on samsung s3. Really annoying.. why do I have this problem and not you?
-
Johan about 10 yearsI get onActivityResult before picture is selected and no onActivityResult after picture is selected so it does not work for me on samsung s3.
-
nommer about 10 yearsmanagedQuery() is deprecated in API 11, can either use CursorLoader which is a bit overkill for this IMHO, or just use getContentResolver().query() like in Khobaib's answer (stackoverflow.com/a/17285119/2048266)
-
Arun Badole over 9 yearsReally useful answer, should be used for selecting images from "Photos" app.
-
Arun Badole over 9 yearsI tried this on both local & server's files, worked for both.
-
Narendra Singh about 9 years@hcpl whats the "action" in if (Intent.ACTION_SEND_MULTIPLE.equals(action))?
-
Narendra Singh about 9 years@hcpl trying to pick multiple images .........it return null, java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=65538, result=-1, data=Intent { dat=content://media/external/images/media/1944 flg=0x1 }} to activity {com.abs_ind.www.example/com.abs_ind.www.example.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.Iterator java.util.ArrayList.iterator()' on a null object reference
-
hcpl almost 9 years@DroidWormNarendra action should've been a property on the data (intent) object so use data.getAction() there instead. I'll update code example.
-
Takermania almost 9 yearsThis question has been answered step by step in this tutorial : stackoverflow.com/questions/30506301/…
-
Tom Kincaid over 8 yearsThe multiple image selector is not working for me. It launches the picker and allows multiple selection, but in onActivityResult, data.getAction() is null, and data.hasExtra(Intent.EXTRA_STREAM) is false.
-
Tom Kincaid over 8 yearsThis answer got the uris from multiple selection stackoverflow.com/questions/21071098/…
-
Alberto Méndez over 8 yearsThe "getPath" method in the "Single Picture Selection" way returns null if the user choose a image from the "Recent" option in the gallery (tried in Lollipop), I solved it by directly using the Uri
-
Craig Russell about 8 yearsAs a previous comment also addresses,
Intent.hasExtra
is a mistake in the post and should be updated todata.hasExtra
. I tried to edit it to this effect but my edit was rejected; not sure why as the current code wouldn't compile and only serve to confuse people further. -
Pankaj almost 8 yearsIt's working for me I am using Nexus 5 with Marshmallow. Which phone you are using.
-
Erum almost 8 yearsi m also usng google nexus but faled to get image name or path of my gallery selected image i m getting null
-
Erum almost 8 yearsjava.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/images/media from pid=31332, uid=11859 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission() getting this error
-
Pankaj almost 8 yearsYou have add permission which its showing
READ_EXTERNAL_STORAGE
-
Erum almost 8 yearsyes i already have added permission in manifest but i did not add any permission in java files at runtime
-
AbdulMomen عبدالمؤمن almost 8 yearsthis worked with me stackoverflow.com/questions/30004658/…
-
Stoycho Andreev over 7 yearsI face similar problem and picturePath is always null . I try you solution but does not work , plus that getDocumentId requires > API 19
-
Ankita Shah over 7 yearsThis is working if we picked image from recent images from image pick intent. Not working when user picked image from gallery.
-
Mr_Anderson over 7 yearsif (Intent.ACTION_SEND_MULTIPLE.equals(data.getAction())&& data.hasExtra(Intent.EXTRA_STREAM)) returns FALSE
-
Derlin over 6 yearsThis is the easiest answer (and the only one that worked for me). So nicely done!
-
Jeremy Caney about 2 yearsThis question has long been answered, and has a few answers that have been repeatedly validated by the community. Why do you prefer this over the existing answers?