Monday, September 28, 2009

Displaying images from SD card in Android

Below you will find a Android example of how to access and display images that are stored on your SD card.

I wrote part 2 for this article, where images are loaded in the background using an asynchronous task. It is an improvement over this article, but I strongly suggest trying this one first to fully appreciate the differences between the two approaches.

The main idea is to make use of the MediaStore class, which is a Media provider that contains data for all available media on both internal and external storage devices (such as an SD card). An adapter is used as a bridge between the data and the view.

The activity is shown below:

package blog.android.sdcard;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.AdapterView.OnItemClickListener;

/**
 * Displays images from an SD card.
 */
public class SDCardImagesActivity extends Activity {

    /**
     * Cursor used to access the results from querying for images on the SD card.
     */
    private Cursor cursor;
    /*
     * Column index for the Thumbnails Image IDs.
     */
    private int columnIndex;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.sdcard);

        // Set up an array of the Thumbnail Image ID column we want
        String[] projection = {MediaStore.Images.Thumbnails._ID};
        // Create the cursor pointing to the SDCard
        cursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
                projection, // Which columns to return
                null,       // Return all rows
                null,
                MediaStore.Images.Thumbnails.IMAGE_ID);
        // Get the column index of the Thumbnails Image ID
        columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID);

        GridView sdcardImages = (GridView) findViewById(R.id.sdcard);
        sdcardImages.setAdapter(new ImageAdapter(this));

        // Set up a click listener
        sdcardImages.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView parent, View v, int position, long id) {
                // Get the data location of the image
                String[] projection = {MediaStore.Images.Media.DATA};
                cursor = managedQuery( MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        projection, // Which columns to return
                        null,       // Return all rows
                        null,
                        null);
                columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                cursor.moveToPosition(position);
                // Get image filename
                String imagePath = cursor.getString(columnIndex);
                // Use this path to do further processing, i.e. full screen display
            }
        });
    }

    /**
     * Adapter for our image files.
     */
    private class ImageAdapter extends BaseAdapter {

        private Context context;

        public ImageAdapter(Context localContext) {
            context = localContext;
        }

        public int getCount() {
            return cursor.getCount();
        }
        public Object getItem(int position) {
            return position;
        }
        public long getItemId(int position) {
            return position;
        }
        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView picturesView;
            if (convertView == null) {
                picturesView = new ImageView(context);
                // Move cursor to current position
                cursor.moveToPosition(position);
                // Get the current value for the requested column
                int imageID = cursor.getInt(columnIndex);
                // Set the content of the image based on the provided URI
                picturesView.setImageURI(Uri.withAppendedPath(
                        MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, "" + imageID));
                picturesView.setScaleType(ImageView.ScaleType.FIT_CENTER);
                picturesView.setPadding(8, 8, 8, 8);
                picturesView.setLayoutParams(new GridView.LayoutParams(100, 100));
            }
            else {
                picturesView = (ImageView)convertView;
            }
            return picturesView;
        }
    }
}
The layout of the main activity is shown below:

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/sdcard"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:padding="10dp"
    android:verticalSpacing="10dp"
    android:horizontalSpacing="10dp"
    android:numColumns="auto_fit"
    android:columnWidth="90dp"
    android:stretchMode="columnWidth"
    android:gravity="center"
/>

In order for this to work, you need to emulate an SD card.

Enjoy!

UPDATE (October 19, 2009): In order to be bale to view thumbnails images from the SD Card, Android needs to create them first, hence you should start the Gallery application that comes preinstalled, and open the sdcard folder which will automatically create thumbnails for the images stored on your sdcard. This is a current shortcoming of the SDK that will be fixed in future releases (http://groups.google.com/group/android-developers/browse_thread/thread/3f01b284e2537312/fa9487d19db4907e).

UPDATE (October 07, 2009): For some reason, if you use
MediaStore.Images.Thumbnails.IMAGE_ID
like in the previous version of the above code, the images are not always displayed on the screen. Changing to
MediaStore.Images.Thumbnails._ID
seems to solve the problem. I will look more into why and get back to you.
Furthermore, some images have the wrong path attached to them.  I changed the creation of the cursor object from
cursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection, // Which columns to return
null,       // Return all rows
null,
null);
to
cursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection, // Which columns to return
null,       // Return all rows
null,
MediaStore.Images.Thumbnails.IMAGE_ID);

56 comments:

Anonymous said...

hi,
I ve done all the necessary corrections on my code but still its not displaying the images... the code is unning and the emulator gets launched but shows only a blank page... please help me out in this code

Mihai Fonoage said...

Have you emulated the sdcard first, started the emulator with that sd card, and pushed the images on the sd card using adb push command properly? If you did all that, when starting the emulator, open the Gallery application that comes with it, and see if it displays the images on the sd card. If it does, try my application again. Post the results back here.

Anonymous said...

hi,

I ve done all wat u ve asked... i ve pushed the images properly but there is some confusion in the null loop or external URI i guess but the pog shows no error only

Anonymous said...

i meant the prog shows no error but i m not getting the desired output

Mihai Fonoage said...

Do you see the images on the sd card when using the Gallery application that comes with the emulator?

Anonymous said...

no i cant c images in the emulator.
its displayed under sdcard in the file explorer
Thanks

Anonymous said...

in that default gallerywith emulator it shows no media found. wat shall i do

Mihai Fonoage said...

OK, so you do not see any images when using the Gallery application, which implies that maybe the sd card was not emulated properly, or loaded properly. If you followed the steps described in the link I provided, you should have created the sd card image and loaded the images properly. When you create a run configuration for your Android project, you have to specify an AVD for deployment (under the Target tab in run configurations). You have to create one and link to the sd card image you previously created. More info on how to achieve this can be found at http://developer.android.com/guide/developing/eclipse-adt.html#CreatingAnAvd. After you're doen with this, make sure you will use that AVD when starting the emulator and/or launching your application. Always use the Galley application first to make sure that everything works out, then try my application.

Mihai Fonoage said...

I just re-tested the code I posted and it works fine for me (sdk 1.0 and 1.6), so make sure you follow all the necessary steps.

Hyperjetta said...

Hello, very nice demo. I got it working on my device first try with no hitches except for one. For some reason it only accesses the first 20 or so images from the sdcard and then builds the gridview with those 20 images repeated over and over for what looks like the total # of images I have on the sdcard. I'm lost as to why that would happen, but I'm pretty new tho this so maybe its an error on my part.

Mihai Fonoage said...

Hi Hyperjetta. Try loading all images from the SD Card with the Gallery application first (which will create a thumbnail for those images), and then use the sample code. Let me know if it solves the problem. I plan to post an update (improvement) for this post in the near future.

Hyperjetta said...

Hmm, didn't seem to help. I'm testing the app on my phone which has 400 pictures on it. All the thumbnails load normally in the gallery.

Mihai Fonoage said...

All images have to be loaded in the Gallery application (you actually have to wait until all are loaded, which means you see the thumbnails being displayed on the screen). If you are still having problems after that, I will write a follow up for this post that I am hoping does not have the same issues as this one. By the way, what phone are you using?

Mihai Fonoage said...

I wrote part 2 for this article.

vasu said...

Hi,

I wanted to display all the images of res/drawable folder in gridview.How can I achieve dis without specifying all the Thumb Ids in an Integer array?.

Mihai Fonoage said...

Hi vasu,

I am not aware of any other way to achieve what you want. My suggestion is to post this question in the android developers forum.

vasu said...

Hi Mihai Fonoage,
Thanks for response.Can we access the images of Drawable or Assests folder by setting URI as like u did for Displaying images from SD card?.Give me a good idea to set the URIs for different locations with examples(for internal and external folders).

elcoqui said...

I was wondering if there was any way to pass an array of the image files to the gallery view since I am looping through the sdcard to find ALL image files. That way all the image files get loaded on the view.

Mihai Fonoage said...

The gallery view (grid view) works together with an adapter. If you have an array of image files, you would need to use an image view together with those image files, something similar to what you have in Grid2.java.

Now, having said that, I still believe that the best way to display all images from the SD Card is through the use of an AsynchTask, coupled with an Adapter, as I showed in http://mihaifonoage.blogspot.com/2009/11/displaying-images-from-sd-card-in.html, since it will display one image at a time, loading them in the background.

MIke said...

is this working in actual device???
i have tested this in MY HTC TATTOO but only a blank screen displayed???

Mihai Fonoage said...

Try part 2 of the article, and make sure you have thumbnails created because the code uses MediaStore.Images.Thumbnails (open the Gallery app on your phone and see if it detects any images on your SD Card, and by doing so it will automatically create thumbnails of those images).

Anonymous said...

Hi there, that's a great code!

But I got a question: how would I get it working with videos?? I am really new to Android and I am a bit stuck there...

Thanks

Mihai Fonoage said...

Look into http://developer.android.com/reference/android/provider/MediaStore.Video.html.

abhinandkr said...

Hi,
Thanks very much for this guide. It works wonderfully on my phone, running Android API level 7.
However, it displays an image multiple times. It displays the set of all images once, then it repeats that set few more times. How do I get it to display them only once?

Mihai Fonoage said...

I'm glad you find it useful. For the problem you have, look into part 2 of this article. You have a link at the beginning of the post.

Anonymous said...

Excellent..I have been looking for this for some time. It helped me. Thanks.

And, by the way, please mention that you named the xml file as "sdcard.xml" . I had to change the name from default "main.xml" to "sdcard.xml" only after I was thrown an error. Thanks again.

Anonymous said...

what is the code to insert images into the sdcard?

after inserting, just follow this example to display it right?

sorry im very new to android, this is totally advance.

Anonymous said...

hi, i am new on android, i want to display gallery images in my application also when i click an image it should open for editing. your SDcard code only displays the images but can't open them, plz help me.
Thank You!

OwenRay said...

thank you for you article it was very helpful, however I do have an addition. Androids Adapter works like this; when you scroll he reuses old elements by passing them to getview, but you return the old element, this creates duplicates..
so the correct way to do this is:

public View getView(int position, View convertView, ViewGroup parent) {
cursor.moveToPosition(position);
int imageID = cursor.getInt(columnIndex);

ImageView picturesView = convertView==null?new ImageView(context):(ImageView) convertView;

picturesView.setImageURI(Uri.withAppendedPath(
MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, "" + imageID));

if(picturesView==null){
picturesView.setScaleType(ImageView.ScaleType.FIT_CENTER);
picturesView.setPadding(8, 8, 8, 8);
picturesView.setLayoutParams(new GridView.LayoutParams(100, 100));
}

return picturesView;
}

OwenRay said...

little mistake in my last comment

if(picturesView==null){

should be

if(convertView==null){

Mihai Fonoage said...

@OwenRay
I fixed that in part 2 of my article. There is a link to that at the beginning of the blog, or you can go directly from here: http://mihaifonoage.blogspot.com/2009/11/displaying-images-from-sd-card-in.html

Anonymous said...

That helped me solve the "java.lang.OutOfMemoryError: bitmap size exceeds VM budget" problem - I used this code to get the thumb for each URI and put the thumb into my gallery widget. I maintain the URIs in the adapter so I can get the full size images one at a time. Perfect - thanks!

kandula said...

hi,
plz help me to create a slideshow of images which are present in sdcard

DaniB said...

Hi, I have tried your code but it crashes. Please help troubleshoot.

DaniB said...
This comment has been removed by the author.
DaniB said...

Hi, I have tried using this code, but I have been having a lot of problems. My AVD has a sd card and I was able to push files onto it. However, I got some serious errors with the Image Adapter when trying to run this code. I had to create a new object from the main activity class so that I would be able to user the cursor in Main activity. Then, when my code finally seemed error-free, I tried to run it and all I see being displayed is a textview at the top. Please me solve this problem that I have been struggling with for a while.

Mihai Fonoage said...

Hi Dani,

Have you tried the improved version of this code: http://mihaifonoage.blogspot.com/2009/11/displaying-images-from-sd-card-in.html

Let me know if that works for you!

DaniB said...

Hi Mihai,

I tried your improved version but still getting a black screen. I really don't know what could be the problem. Any suggestions?

mehdok said...

hi every boy ,
i am using ListActivity for my VIEW and extends ArrayAdapter to inflate rows,
for each row i need thumbnail, i using some part of MIHAI code but i got the wrong thumbnail
i using below code :

public View getView(int position, View convertView, ViewGroup parent)
{
.
.
.
.
.
Long Imageid = getItemId(position);
Uri imageUri = Uri.withAppendedPath(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, "" + imageId);
try
{
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
if(bitmap != null)
{
Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap, width, width, true);
bitmap.recycle();
icon = newBitmap;
}
else
icon = null;
}
catch(IOException e)
{

}
}

any help ?

Anonymous said...

In the progaram it shows the error "The local variable imagePath is never read".Why it is so?

Asha said...

@Mihai ,In the above program which you wrote to display images from sd card, I am getting a warning in the code "Multiple markers at this line
- Line breakpoint:Grid2 [line: 53] - onItemClick(AdapterView, View,
int, long)
- The local variable imagePath is never read"
Please help me to resolve this.

vipankumar said...

can anybody please send me a download link for working code of this example I am newbeas in android development i am very frasted so please help me
Thanks in advance

Anonymous said...

I am trying to view the images on Motorola Xoom. I would like to access the photos in the pictures folder. I am unable to find any documentation on how to do that? Any pointers would be greatly appreciated.

ragupathi said...

Hi mihai,

Im developing one grid view program and displayed some images its working fine.. when i click one images that time to display that image in fullscreen when i scroll left or right i need to load back or previews image... i need to show all the images one by one...

sukesh said...

Hie I am new to android.. Ur tutorial was awesome. It worked for me. Now i am working on a video app. Getting all the Videos from the sd-card. I am able to get the thumb images. But the main problem is after clicking on the thumbnail, the respective video must be played. Actual video is not playing. after clicking on end of the GalleryView. IndexoutofBounfException error is occuring Can u please help me out..

Android app development said...

This is one of the fantastic post.I like your blog status.Thanks for presenting this kind pf Information.This is one of the challenging post.Android app developers

pratik said...

Hi..
This is a good example..
But what if i want to fetch images from the specific folder other than default folder where images stored...

suppose i have a folder "/sdcard/myimage/*.jpg"
what should i do to display only those images...??
Pls reply as soon as possible

pratik said...

Hi..
This is a good example..
But what if i want to fetch images from the specific folder other than default folder where images stored...

suppose i have a folder "/sdcard/myimage/*.jpg"
what should i do to display only those images...??
Pls reply as soon as possible

Anonymous said...

Hi
When i click on the image im not getting the enlarged image.

i have used
imageview.setImageResource(projection[position])

projection is the string array

Android app developers said...

This is one of the brilliant post.Your blog is presenting very satisfactory information.This is one of the supportive post.

Android app developers said...

This is one of the satisfactory post.I like your blog features.This is one of the good application.

zeltera said...

Hi Mihai,

In my case I cannot get the path to the original image (the one who's thumb i get in the cursor).

This part of the code:

String path = cursor.getString(columnIndexPath);
Uri imgThmbPath = Uri.withAppendedPath( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, ""
+ imageID);

returns me something like this (in imgThmbPath ): content://media/external/images/thumbnails/1

This can't be the full image, the original one. How do I get the path to the original image?

Vivian Richard said...

How do i get my android to download to my micro sd card?
My phone likes to save stuff on my phone's memory and i want the stuff saved on my sd card. I have android 2.2.
thanks;
App Development Company

clarke said...

i am really new to android
I am trying to get images from sd card in gridview in android and to display them when clicked
I have tried this program but there is a problem with the output

there is no error showing in the program but am not getting the required output
please give me relevant answer

Rahul Shah said...

i want to select multiple images from sdcard and store in sqlite database ...and retrieve back from sqlite view in gridview....i tried to do this from 15 days but can't make... can anyone help me...??

Vinod Gehlot said...

hi..
i have all images of sd card in list view and i want to open each image when i clicked on to that.
what should i do...
please help me out in this code.