In one of my previous posts, I wrote about how to fetch and display images from the SD card. The problem with the previous post is that one would have to wait until the first couple of images are available and shown on the screen. This implies that when the user wants to see the images, he will wait a couple of seconds until the first screen of images is available. The code that I'm going to post here works more like the Gallery application, meaning that one image at a time will be displayed on the screen. To achieve this effect, I used an AsyncTask, which fetches one image at a time in the background, and adds that image to the grid view during the progress update.
package blog.android.sdcard2;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.AdapterView.OnItemClickListener;
/**
* Loads images from SD card.
*
* @author Mihai Fonoage
*
*/
public class LoadImagesFromSDCardActivity extends Activity implements
OnItemClickListener {
/**
* Grid view holding the images.
*/
private GridView sdcardImages;
/**
* Image adapter for the grid view.
*/
private ImageAdapter imageAdapter;
/**
* Display used for getting the width of the screen.
*/
private Display display;
/**
* Creates the content view, sets up the grid, the adapter, and the click listener.
*
* @see android.app.Activity#onCreate(android.os.Bundle)
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Request progress bar
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.sdcard);
display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
setupViews();
setProgressBarIndeterminateVisibility(true);
loadImages();
}
/**
* Free up bitmap related resources.
*/
protected void onDestroy() {
super.onDestroy();
final GridView grid = sdcardImages;
final int count = grid.getChildCount();
ImageView v = null;
for (int i = 0; i < count; i++) {
v = (ImageView) grid.getChildAt(i);
((BitmapDrawable) v.getDrawable()).setCallback(null);
}
}
/**
* Setup the grid view.
*/
private void setupViews() {
sdcardImages = (GridView) findViewById(R.id.sdcard);
sdcardImages.setNumColumns(display.getWidth()/95);
sdcardImages.setClipToPadding(false);
sdcardImages.setOnItemClickListener(LoadImagesFromSDCardActivity.this);
imageAdapter = new ImageAdapter(getApplicationContext());
sdcardImages.setAdapter(imageAdapter);
}
/**
* Load images.
*/
private void loadImages() {
final Object data = getLastNonConfigurationInstance();
if (data == null) {
new LoadImagesFromSDCard().execute();
} else {
final LoadedImage[] photos = (LoadedImage[]) data;
if (photos.length == 0) {
new LoadImagesFromSDCard().execute();
}
for (LoadedImage photo : photos) {
addImage(photo);
}
}
}
/**
* Add image(s) to the grid view adapter.
*
* @param value Array of LoadedImages references
*/
private void addImage(LoadedImage... value) {
for (LoadedImage image : value) {
imageAdapter.addPhoto(image);
imageAdapter.notifyDataSetChanged();
}
}
/**
* Save bitmap images into a list and return that list.
*
* @see android.app.Activity#onRetainNonConfigurationInstance()
*/
@Override
public Object onRetainNonConfigurationInstance() {
final GridView grid = sdcardImages;
final int count = grid.getChildCount();
final LoadedImage[] list = new LoadedImage[count];
for (int i = 0; i < count; i++) {
final ImageView v = (ImageView) grid.getChildAt(i);
list[i] = new LoadedImage(((BitmapDrawable) v.getDrawable()).getBitmap());
}
return list;
}
/**
* Async task for loading the images from the SD card.
*
* @author Mihai Fonoage
*
*/
class LoadImagesFromSDCard extends AsyncTask<Object, LoadedImage, Object> {
/**
* Load images from SD Card in the background, and display each image on the screen.
*
* @see android.os.AsyncTask#doInBackground(Params[])
*/
@Override
protected Object doInBackground(Object... params) {
//setProgressBarIndeterminateVisibility(true);
Bitmap bitmap = null;
Bitmap newBitmap = null;
Uri uri = null;
// 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 cursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection, // Which columns to return
null, // Return all rows
null,
null);
int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID);
int size = cursor.getCount();
// If size is 0, there are no images on the SD Card.
if (size == 0) {
//No Images available, post some message to the user
}
int imageID = 0;
for (int i = 0; i < size; i++) {
cursor.moveToPosition(i);
imageID = cursor.getInt(columnIndex);
uri = Uri.withAppendedPath(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, "" + imageID);
try {
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
if (bitmap != null) {
newBitmap = Bitmap.createScaledBitmap(bitmap, 70, 70, true);
bitmap.recycle();
if (newBitmap != null) {
publishProgress(new LoadedImage(newBitmap));
}
}
} catch (IOException e) {
//Error fetching image, try to recover
}
}
cursor.close();
return null;
}
/**
* Add a new LoadedImage in the images grid.
*
* @param value The image.
*/
@Override
public void onProgressUpdate(LoadedImage... value) {
addImage(value);
}
/**
* Set the visibility of the progress bar to false.
*
* @see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
@Override
protected void onPostExecute(Object result) {
setProgressBarIndeterminateVisibility(false);
}
}
/**
* Adapter for our image files.
*
* @author Mihai Fonoage
*
*/
class ImageAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<LoadedImage> photos = new ArrayList<LoadedImage>();
public ImageAdapter(Context context) {
mContext = context;
}
public void addPhoto(LoadedImage photo) {
photos.add(photo);
}
public int getCount() {
return photos.size();
}
public Object getItem(int position) {
return photos.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
final ImageView imageView;
if (convertView == null) {
imageView = new ImageView(mContext);
} else {
imageView = (ImageView) convertView;
}
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setPadding(8, 8, 8, 8);
imageView.setImageBitmap(photos.get(position).getBitmap());
return imageView;
}
}
/**
* A LoadedImage contains the Bitmap loaded for the image.
*/
private static class LoadedImage {
Bitmap mBitmap;
LoadedImage(Bitmap bitmap) {
mBitmap = bitmap;
}
public Bitmap getBitmap() {
return mBitmap;
}
}
/**
* When an image is clicked, load that image as a puzzle.
*/
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
int columnIndex = 0;
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection,
null,
null,
null);
if (cursor != null) {
columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToPosition(position);
String imagePath = cursor.getString(columnIndex);
FileInputStream is = null;
BufferedInputStream bis = null;
try {
is = new FileInputStream(new File(imagePath));
bis = new BufferedInputStream(is);
Bitmap bitmap = BitmapFactory.decodeStream(bis);
Bitmap useThisBitmap = Bitmap.createScaledBitmap(bitmap, parent.getWidth(), parent.getHeight(), true);
bitmap.recycle();
//Display bitmap (useThisBitmap)
}
catch (Exception e) {
//Try to recover
}
finally {
try {
if (bis != null) {
bis.close();
}
if (is != null) {
is.close();
}
cursor.close();
projection = null;
} catch (Exception e) {
}
}
}
}
}
The sdcard.xml file:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<GridView
android:id="@+id/sdcard"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center" />
</FrameLayout>
That's it. Let me know if you have any questions.
Enjoy!

82 comments:
Hi Mihai,
Can you show me an example of how you would obtain the URI for the image that is selected?
You already have the path to that image in the imagePath variable. Just use a URI constructor that takes a strings as its input and you should be all set.
Hi Mihai,
I have written similar program to show the images(but not thumbnails) from sdcard in emulator, it works fine in emulator but on G1 device, it shows the java.lang.OutOfMemoryError can you guess the problem, and above your program does not show anything when I clicked on image even I have written code to show the image in dialog box
Hi surya's,
My program does not display the image you clicked on. You have to use the scaled bitmap I create from the image that was clicked on(referenced by useThisBitmap) and display it in an image view or something similar.
Regarding your problem, most probably the error results from trying to load a to big of an image. Try scaling the image, or, when decoding the stream, use the BitmapFactory.Options class and set the inSampleSize to some power of 2. Do a search on this on Android Forums and you will get many many similar answers that will help.
Mihai,Thank you
hello
I would like to ask
why the following codes
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setPadding(8, 8, 8, 8);
imageView.setImageBitmap(photos.get(position).getBitmap());
return imageView;
need to be placed out of the if case block
i tried to move them inside
if (convertView == null) {
}
the outcome is that all the bitmap drawn are the same as the first images of the cursor
The idea here is that you want to reuse the ImageView as much as possible to save memory. Once you have the ImageView (a new one for the first image, or a reused one for the rest of the images), you just need to add the new bitmap to it and return it, which will then be displayed in the grid you previously created.
What about reading pictures from a specific folder. e.g Can we read images from "sdcard/myPictures". Thanks for the post. It works fine.
Sure you can, but you would need to use something different than a Cursor, something like creating a file to that directory, using listFiles method to get an array of files from that directory, and then go through each of them, get an input stream, and create your Bitmap.
Mihai thank you for your quick response. I have developed application as you pointed out but it crashes sometimes on start, not always. I have used AsyncTask as you wrote, while reading pictures from specific folder. I suppose you have seen such an error. Do you have any idea which event triggers app crash on start. Thank you again.
Actually, I am using the method mentioned and it did not crash on me yet. You have to be more specific on what error you get. Look into LogCat and see what error messages you get. The code that I use is similar to the one below:
File imagesDir = new File(Environment.getExternalStorageDirectory().toString() + "/YOUR_DIRECTORY");
imageList = imagesDir.listFiles();
for (File image : imageList)
try {
bitmap = BitmapFactory.decodeStream(image.toURL().openStream());
//use bitmap and recycle afterwards
} catch (IOException e) {
e.printStackTrace();
}
Mihai, i found the error.
setProgressBarIndeterminateVisibility(true);
This function execution must be on UI side. Which means you can not call it in doInBackground. I have placed it just before loadImages() and it solved my issues. Now i am able to debug on emulator and run program on horizontal layout.
One more thing is that why you have called grid.getChildCount(); instead of grid.getCount(); at onRetainNonConfigurationInstance. If you flip screen from vertical layout to horizontal layout then some of the pictures will be missed.
You are right, there is no reason not to call getCount instead of getChildCount, since all children views (not only the visible ones) should be "freed". Thanks for pointing that out.
Could you please elaborate more on how to display pics from a specific folder on the SDCard? Thanks!
Use something like
File imagesDir = new File(Environment.getExternalStorageDirectory().toString() + "/pathToDirectory");
File[] imageList = imagesDir.listFiles();
for (File imagePath : imageList) {
bitmap = BitmapFactory.decodeStream(imagePath.toURL().openStream());
}
How will the list of images (bitmap) be then integrated with the galleryview? I am sorry if this is a newbie question. I was not able to find this information online.
To clarify further, I am interested in retrieving the name of the file once the gallery view displays images from a specific folder. Thanks!
Please ignore my previous comments. I actually got a version to work based on your previous reply!
Here are my changes:
File imagesDir = new File(Environment.getExternalStorageDirectory().toString() + "/mydir");
imageList = imagesDir.listFiles();
In onItemClick (to get the
selected file path):
-----------------------
String imagePath = imageList[position].getAbsolutePath();
In ImageAdapter:getView:
-----------------------
imageView.setImageBitmap(BitmapFactory.decodeStream(imageList[position].toURL().openStream()) );
Is this the ideal way or am I missing out on any optimizations?
Hi Mihai,
I am using your code imagesload from sdcard ...its working fine
Thanks.....but if i am using in gallery and grid view at a time then generate run time exception outofmemory and Async threadPoolExecutor ...so how can I solve this issue ???can you guide me please ...thanks
Hello Mihai,
My goal is to post on FaceBook an image picked from the sdcard.
To connect to FaceBook I use this code an I try to send the chosen image like in their example, passing as image source the URI of my picture.
Using your code, I get the uri ("content://media/external/images/thumbnails") and the imagePath ("/sdcard/DCIM/.thumbnails/1273763440079.jpg"), which I tried to pass as image source.
I also tried to use Uri.parse("file://"+ imagePath), resulting in "file:///sdcard/DCIM/.thumbnails/1273763440079.jpg".
As a last attempt, I passed even "file:///sdcard/myImage.jpg"
Well, none of the above works and I don't have any idea what I should do.
Please, could you give me a piece of advice?
Thank you a lot, I am very gratefull for any hint.
Hi Mihai,
Great source code. I need one help on showing html file from SD card. I have a html files stored on SD card and simply want to show on view or Browser. Could you please help me.
hi Mihai,
this works fine, so could please tell me how to load videos as well as audio files
regards,
MIke
very good work ......
i used this code for image viewer and now i try to send selected image to picasa via email so i need to open email activity with selected image as attachment ,i try lot but it not done ,can you help me on that ....i share my code
public void onItemClick(AdapterView parent, View v, int position, long id) {
int columnIndex = 0;
int position =0;
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = managedQuery( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection,null,null, null);
if (cursor != null)
{ columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToPosition(position);
String imagePath = cursor.getString(columnIndex);
final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("jpeg/image");
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{picasa_id+"."+secret_word+"@picasaweb.com"});
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, album_name);
emailIntent.putExtra(android.content.Intent.EXTRA_STREAM,Uri.parse(imagePath));
Toast.makeText(this, "please atteched the image file", 10000).show();
this.startActivity(Intent.createChooser(emailIntent, "Send mail..."));
finish();
}
this code work fine but when i send that mail to picasa a a diffent image is display .......or null image in place of selected image?
thanx ....
sumit
Thank for the code
it's working fine.
When i try to add a function that include
Cursor cursor = getContentResolver().query(People.CONTENT_URI, null, null, null, null);
it crash , this function work fine
in other application
do you have ant idea why the cursor crash ?
Hi Mihai,
I am working on an application which require
1. select an image folder
2. display the images in the folder in a GridView.
I am wondering, if you know of any example of Gallery for folder selection?
to use the sdcard you can do it like this change sSDcardLooky
to your folder
protected Object doInBackground(Object... params) {
setProgressBarIndeterminateVisibility(true);
Bitmap bitmap = null;
Bitmap newBitmap = null;
Uri uri = null;
imageList.clear();
if(imageList.size()==0){
boolean exists = (new File(sSDcardLooky)).exists();
if (exists)
{ // File or directory exists }
//Toast.makeText(this, "exist", Toast.LENGTH_SHORT).show();
}
else { // File or directory does not exist }
//Toast.makeText(this, "not exist", Toast.LENGTH_SHORT).show();
}
// Search sdcard/image catalog picture file , As the gallery source ,
File sdcard=new File(sSDcardLooky);
//Log.d(TAG,"Gallery1.sdcard."+sdcard.getName());
File[] imageFiles=sdcard.listFiles(new FileFilter(){
public boolean accept(File arg0){
String fileName=arg0.getName();
String ex=arg0.getName().substring(fileName.lastIndexOf(".")+1,fileName.length()).toLowerCase();
if(ex==null||ex.length()==0){
return false;
}else{
if(ex.equals("jpg")||ex.equals("bmp")||ex.equals("png")||ex.equals("gif")){
return true;
}
return false;
}
}
});
for(int i=0 ; i<imageFiles.length ; i++){
File file=imageFiles[i];
//Log.d(TAG,"Gallery1.file abs Path."+file.getAbsolutePath()+" path."+file.getPath());
// vViewPic(imageFiles[i].getName());
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
if (bitmap != null) {
newBitmap =
Bitmap.createScaledBitmap(bitmap, 70, 70, true);
bitmap.recycle();
if (newBitmap != null) {
publishProgress(new LoadedImage(newBitmap));
}
}
//imageList.add(BitmapFactory.decodeFile(file.getAbsolutePath()));
//sf = file.getAbsolutePath();
//Toast.makeText(this, sf, Toast.LENGTH_SHORT).show();
//vViewPic("file://"+sf);
}
}
return null;
}
Hi Mihai:
GREAT WORK!!!!!
Your code helped me a lot!
Thank you!!
correct me if I'm wrong but you are caching all images that are displayed in the gridview ? so if there are 500 images in scard you cached those 500 images in the ArrayList, right ?
If that is the case then isn't that problem, the phone will run out of memory ?
Yes I am, but it is a scaled version of the initial image, not the actual image. And if there is no more memory and the Activity gets destroyed, I free up the resources related to each bitmap. In the future, I could probably only cache the images that are currently visible on the screen, do some lazy initialization, and reuse the bitmaps that are no longer visible, something similar to how a UITableViewCell is reused on the iPhone.
Can you write pseudo-code of the idea that you mentioned ?
Thanks
Hey there... I've seen alot of posts on how to utilize your code with a specific directory, but am having a hard time actually implementing the change. Could you help? However, thanks again for the great post. This method is lightning fast!
Hi Mihai,
The code from part 1 worked, although it is not displaying all the images.
In this part 2 code, it is giving an exception while in doInBackground().
Here is the message:
"android.View.viewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."
What can I do to correct it? I don't see any explicit thread creation anywhere.
Hi Mihai,
I corrected my previous problem.
Anyway, I want to enhance this code by making it like the Media Gallery. I want to put a checkmark on the photo, when it is touched. Basically, a Select Image feature. How do I do that?
I created a new GridView above the existing one, which takes in the Bitmap of the selected image, but I unable to refresh the screen. Besides, that can be too costly.
Can you help me, please?
Need remove the line 157 - setProgressBarIndeterminateVisibility(true); - , which is throwing an exception. And then it works really nice!
@Tom and @c group - Thanks for the setProgressBarIndeterminateVisibility(true); issue, I made the suggested changes.
Hi Mihai,
I couldn't find any contact information on the blog, I made an app using some part of it and I would like to thank you for sharing it!!!
Hi Mihai I'm working on an image manipulation framework and was using some other method to bring out thumbnails. I wanted to thank you because the method you're using with AsyncTask is superior and I will incorporate it in the framework.
I'm also using the MediaScannerConnection to solve the issue with thumbnail creation of new images on the SDCARD and it works pretty well. Here's the function I created for that:
private void scanMedia(){
String[] sdFiles=null;
File sdPath = Environment.getExternalStorageDirectory();
File[] sdImageArray = sdPath.listFiles(new FilenameFilter(){
@Override
public boolean accept(File dir, String name)
{
return ((name.endsWith(".jpg"))||(name.endsWith(".png")));
}
});
sdFiles = new String[sdImageArray.length];
for(int i= 0 ; i< sdImageArray.length; i++)
{
sdFiles[i] = sdImageArray[i].getAbsolutePath();
}
MediaScannerConnection.scanFile(this, sdFiles, null, null);
}
It should create an array of paths to all the images and make the MediaScannerConnection generate thumbnails for the new ones that haven't been added, solving the thumbnail generation issue.
Thanks again,
Francisco J. Consuegra
Hi Francisco. I'm glad you decided to continue working on the framework. Thanks for the code also; an alternative would be calling the compress method from the Bitmap class to create a 'thumbnail' image on the SD card.
Hi Sir,
It was wonderful piece of code, both part 1 and part 2. Thanks for sharing.
But i have some different requiremnet.
I have went through couple of forums but everybody are showing to display images from SD card.
My app requires that i click on a link,which has 'n' number of photos,and populate all the photos, in a grid view.
I am stuck , can you pls provide any help.
Excellent article. Helped me clarify some issues with a project I am researching.
BTW, check out our blog at : http://appfulcrum.com/?page_id=153
You got this code sample on Github or Google Code? I wanna try it out.
I cant see the progress bar.
Is it supposed to be so?
I want to have progress bar until all the images be loaded. because if you click on an image or press back button anytime before all the images become loaded, it throws exception.
thank you,
it was nice article.
I cant see the progress bar.
Is it supposed to be so?
I want to have progress bar until all the images be loaded. because if you click on an image or press back button anytime before all the images become loaded, it throws exception.
thank you,
it was nice article.
I cant see the progress bar.
Is it supposed to be so?
I want to have progress bar until all the images be loaded. because if you click on an image or press back button anytime before all the images become loaded, it throws exception.
thank you,
it was nice article.
Awesome Link........ Very helpful.... Thanks a lot for sharing it... :)
For some reason I had to add a button at the end of sdcard.xml. Otherwise the call
setContentView(R.layout.sdcard);
would fail.
Hi Mihai,
Thanks for the post. It works fine. When orientation of phone changes during loading of images the application crashes due to
java.lang.RuntimeException: An error occured while executing doInBackground()
Could you Please help me
Hi,
hey i want to display the image selected from sd card into email body and not as an attachment. i tried lots of code still i am not able to solve the problem....if you hav solution plz help me...
Thank you in anticipation
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 ?
great job mihai!
Hi Mihai,
iam very much beginner in android. can u tell me that how to create folders in sdcard.and storing the camera pictures in the folder which i am created.and too i want create the folder it should want to dynamic.
Hi
I have used this code without following code
File imagesDir = new File(Environment.getExternalStorageDirectory().toString() + "/pathToDirectory");
File[] imageList = imagesDir.listFiles();
for (File imagePath : imageList) {
bitmap = BitmapFactory.decodeStream(imagePath.toURL().openStream());
}
But no images are getting loaded.
Can yo please help me?
Hi
I have used this code WITH following code
< sorry for the last post..it was by mistake>
I have used BELOW code
File imagesDir = new File(Environment.getExternalStorageDirectory().toString() + "/pathToDirectory");
File[] imageList = imagesDir.listFiles();
for (File imagePath : imageList) {
bitmap = BitmapFactory.decodeStream(imagePath.toURL().openStream());
}
But no images are getting loaded.
Can yo please help me?
Hi ,
This code helped me a lot .But I am facing a small problem . I am getting duplicate images while displaying the images but when i checked in SD card only one image is stored . Can you pls help me how to retrieve only original image and remove this duplicacy .
Thank You
The code crashes if you click GO-BACK button meanwhile the images are appearing on the phone
Could you point some hints howto solve this situation ?
Thanks in advance
Hi,
I'm new comer in Android, I copy your code and build but it shows error, and when I debug, it fails in function setupViews(): sdcardImages = (GridView) FindViewById(R.id.sdcard);
Please help me, how can I fixed that. I'm using android API 2.2 and run on Desire.
Thanks
Nguyen
Hi Mihai, thanks for your code.
I have a question, I would load many images in async way in a gridview, but for every image I have three TextView related.
How can I load images? Images's uri and text of TextView are retrived from content provider.
Great tutorial.
But I have a problem, when I flip the screen (from horinzontal to vertical por example),
I lost the position of my pictures...
So when I click in one of them, the position return null and the aplication return error..
How Can I store the pictures position ?
This is my function that return null when I flip the screen :
public void onItemClick(AdapterView parent, View v, int position, long id) {
Toast.makeText(AsynImagesSDCARDActivity.this, "" + item.get(Integer.toString(position)), Toast.LENGTH_SHORT).show();
}
As c.groud said getChildCount() only show the pictures that are shown in the screen...
I change this for grid.getCount(); but I get an error in this line
final ImageView v = (ImageView) grid.getChildAt(i);
because only is recognized the pictures shown in the srcreen and I obtain null values..
How Can I change this line to obtain all the images ??
Thank you!!
imageAdapter.addPhoto(image);
imageAdapter.notifyDataSetChanged();
I used very similar code as yours for an application I have. It allows you to select an item in a listview. The two lines above get called per image on the main thread. As a result selecting an image is often blocked out until they are done loading. I haven't found a fix to this yet. Any ideas?
Hi Mihai,
first of all, thanks for the tutorials. really helpful. but i don't know if its only me but the code seem to run slow and scrolling is jerky too. i only changed for MediaStore.Images.Media.EXTERNAL_CONTENT_URI since some htc phones with senseUI have an issue with thumbnails and have used bitmap options to reduce size but still very slow. Have any idea on why this could be happening. Once again, Thanks for the tutorials.
hi,i got error after running the code.please help me to fix this
11-24 12:31:30.251: W/dalvikvm(610): threadid=7: thread exiting with uncaught exception (group=0x4001d800)
11-24 12:31:30.351: E/AndroidRuntime(610): FATAL EXCEPTION: AsyncTask #1
11-24 12:31:30.351: E/AndroidRuntime(610): java.lang.RuntimeException: An error occured while executing doInBackground()
11-24 12:31:30.351: E/AndroidRuntime(610): at android.os.AsyncTask$3.done(AsyncTask.java:200)
11-24 12:31:30.351: E/AndroidRuntime(610): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
11-24 12:31:30.351: E/AndroidRuntime(610): at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
11-24 12:31:30.351: E/AndroidRuntime(610): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
11-24 12:31:30.351: E/AndroidRuntime(610): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
11-24 12:31:30.351: E/AndroidRuntime(610): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
11-24 12:31:30.351: E/AndroidRuntime(610): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
11-24 12:31:30.351: E/AndroidRuntime(610): at java.lang.Thread.run(Thread.java:1096)
11-24 12:31:30.351: E/AndroidRuntime(610): Caused by: java.lang.NullPointerException
11-24 12:31:30.351: E/AndroidRuntime(610): at MihaiBlog.com.MihaiBlogActivity$LoadImagesFromSDCard.doInBackground(MihaiBlogActivity.java:170)
11-24 12:31:30.351: E/AndroidRuntime(610): at android.os.AsyncTask$2.call(AsyncTask.java:185)
11-24 12:31:30.351: E/AndroidRuntime(610): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
11-24 12:31:30.351: E/AndroidRuntime(610): ... 4 more
hi mihai
i just run your code and get the following error
11-28 12:56:48.571: ERROR/AndroidRuntime(200): Uncaught handler: thread AsyncTask #1 exiting due to uncaught exception
11-28 12:56:48.641: ERROR/AndroidRuntime(200): java.lang.RuntimeException: An error occured while executing doInBackground()
11-28 12:56:48.641: ERROR/AndroidRuntime(200): at android.os.AsyncTask$3.done(AsyncTask.java:200)
11-28 12:56:48.641: ERROR/AndroidRuntime(200): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
11-28 12:56:48.641: ERROR/AndroidRuntime(200): at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
11-28 12:56:48.641: ERROR/AndroidRuntime(200): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
11-28 12:56:48.641: ERROR/AndroidRuntime(200): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
11-28 12:56:48.641: ERROR/AndroidRuntime(200): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
11-28 12:56:48.641: ERROR/AndroidRuntime(200): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
11-28 12:56:48.641: ERROR/AndroidRuntime(200): at java.lang.Thread.run(Thread.java:1096)
11-28 12:56:48.641: ERROR/AndroidRuntime(200): Caused by: java.lang.NullPointerException
11-28 12:56:48.641: ERROR/AndroidRuntime(200): at com.cls.load.LoadImagesFromSDCardActivity$LoadImagesFromSDCard.doInBackground(LoadImagesFromSDCardActivity.java:180)
11-28 12:56:48.641: ERROR/AndroidRuntime(200): at android.os.AsyncTask$2.call(AsyncTask.java:185)
11-28 12:56:48.641: ERROR/AndroidRuntime(200): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
11-28 12:56:48.641: ERROR/AndroidRuntime(200): ... 4 more
Error belongs to the line
int columnIndex = cursor .getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID);
Hi mihai
Thanks for the tutorial
i just change the _ID to IMAGE_ID in the query and it run fine.
Here is one thing very strange for me that i have a image of size of 3mb in sdcard. This program did not load that image at all. Is there any kind of memory check before loading the image.
I want to load that big image on the click.
Salutare, mersi mult de idee,mi-ai lamurit foarte bine cateva aspecte cu articolul asta!
Hello Mihai, I've been follow your blog for a while man, nice work. My question is that I'm using some of your code to load some images from the user's phone in a gridview as you did above. But can you give an example of how to use the imagePath member? I need to get the path to the fullsized image in the MediaStore based on that imagePath member or some other method, any guidance on this issue?
how can i zoom in the images ?
This code is really inefficient. You are generating two bitmaps and one is rescaled first in the generation and the second one in the view. Come on! The thumbnail has already been generated by the android system (be it gallery or whatever), just pick it up :
bitmap = MediaStore.Images.Thumbnails.getThumbnail(getContentResolver(),imageID,MediaStore.Images.Thumbnails.MICRO_KIND,
(BitmapFactory.Options) null);
There are two types of thumbnails available:
MINI_KIND: 512 x 384 thumbnail
MICRO_KIND: 96 x 96 thumbnail
hai mihai,
i have one problem please clarify, i need to get the image from sdcard and create animation frame using that image. i post my code please clear the error or post your own logic code. please friend clear my doubt
my java code:
import java.io.File;
import java.util.ArrayList;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Environment;
import android.widget.ImageView;
public class FixActivity extends Activity {
/** Called when the activity is first created. */
ImageView image1;
AnimationDrawable animate;
BitmapDrawable bit1,bit2,bit3,bit4;
ArrayList bitmapArray;
File file;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
file = new File(Environment.getExternalStorageDirectory()+"/Pictures/img");
File imageList[] = file.listFiles();
image1=(ImageView)findViewById(R.id.imageView1);
for(int i=0;i();
bitmapArray.add(b);
}
bit1 =new BitmapDrawable(getResources(), bitmapArray.get(0));
bit2 =new BitmapDrawable(getResources(), bitmapArray.get(1));
bit3 =new BitmapDrawable(getResources(), bitmapArray.get(2));
bit4 =new BitmapDrawable(getResources(), bitmapArray.get(3));
int duration1=300;
animate=new AnimationDrawable();
animate.addFrame(bit1, duration1);
animate.addFrame(bit2, duration1);
animate.addFrame(bit3, duration1);
animate.addFrame(bit4, duration1);
animate.setOneShot(true);
image1.setBackgroundDrawable(animate);
animate.setVisible(true, false);
animate.start();
}
}
Mihai Fonoage, Thanks a lot bro...
I modified your code littele bit. coz its not reading the sd card images when i run this code in Tablet.
String[] projection = {"*"};
Cursor cursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI
, projection, null, null, null);
int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID);
int size = cursor.getCount();
Log.d("Cursor size=",""+size);
if (size == 0) {
}
int imageID = 0;
for (int i = 0; i < size; i++) {
cursor.moveToPosition(i);
imageID = cursor.getInt(columnIndex);
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
bitmap = BitmapFactory.decodeFile(path);
if (bitmap != null) {
newBitmap = Bitmap.createScaledBitmap(bitmap, 70, 70, true);
bitmap.recycle();
if (newBitmap != null) {
publishProgress(new LoadedImage(newBitmap));
}
}
}
cursor.close();
return null;
}
HELP:
you are reducing the clarity of the image and putting into the grid. when i click on the image can i view that image in some style with zoom and clarity?
Hi! Great tutorial! I now know much more than early =)
but 1 thing already is deprecated: display.getWidth()/95;
And I think you know what now to get width you need to use "DisplayMetrics"
Thank you anyway.
Hi, Can you Please tell how can I used lastModified() function in it,
I have to get photos I clicked on a particular date,,
But my code is not working
for (int i = 0; i < size; i++)
{
cursor.moveToPosition(i);
imageID = cursor.getInt(columnIndex);
String imagePath = cursor.getString(columnIndex);
File file = new File(imagePath);
Date lastModDate = new Date(file.lastModified());
System.out.println("Today is " + lastModDate );
Date today= new Date();
int results = today.compareTo(lastModDate);
uri = Uri.withAppendedPath(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, "" + imageID);
if(results==-1)
{
try
{
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
if (bitmap != null)
{
newBitmap = Bitmap.createScaledBitmap(bitmap, 70, 70, true);
bitmap.recycle();
if (newBitmap != null)
{
publishProgress(new LoadedImage(newBitmap));
}
}
}
catch (IOException e)
{
//Error fetching image, try to recover
}
}
}
cursor.close();
return null;
}
Hi there,
I would be interested in learning more about how to utilize this process in conjunction with our software for data center infrastructure software.
Mihai Fonoage,you really did gud job.
I use this in my proj bt i have one problem i use onclicklistner in getview when user click on image it works only after all images get load bt i want it work when we adding images too so please help me thanks in advance
This is good job to explain this kind of information through this blog that help me to display images from SD card in Android-part-2.
Dear Mr. Mihai,
I did like your post, but no image display, why that?
I put image into sdCard already.
Post a Comment