Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Showing photos runs out of memory

I'm using a dialog box to display images in my android project. The first one opens fine, but when I close it and do the process again to show a different one the app falls over with a memory error (it's running on a samsung galaxy s3 - so shouldnt be an issue).

Error:

10-24 11:25:45.575: E/dalvikvm-heap(29194): Out of memory on a 31961104-byte allocation.
10-24 11:25:45.580: E/AndroidRuntime(29194): FATAL EXCEPTION: main
10-24 11:25:45.580: E/AndroidRuntime(29194): java.lang.OutOfMemoryError
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:587)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:389)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:418)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.graphics.drawable.Drawable.createFromPath(Drawable.java:882)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.widget.ImageView.resolveUri(ImageView.java:569)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.widget.ImageView.setImageURI(ImageView.java:340)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at com.directenquiries.assessment.tool.AddAsset.loadPhoto(AddAsset.java:771)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at com.directenquiries.assessment.tool.AddAsset$11.onClick(AddAsset.java:748)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at com.android.internal.app.AlertController$AlertParams$3.onItemClick(AlertController.java:936)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.widget.AdapterView.performItemClick(AdapterView.java:292)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.widget.AbsListView.performItemClick(AbsListView.java:1359)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.widget.AbsListView$PerformClick.run(AbsListView.java:2988)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.widget.AbsListView$1.run(AbsListView.java:3783)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.os.Handler.handleCallback(Handler.java:605)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.os.Handler.dispatchMessage(Handler.java:92)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.os.Looper.loop(Looper.java:137)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at android.app.ActivityThread.main(ActivityThread.java:4517)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at java.lang.reflect.Method.invokeNative(Native Method)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at java.lang.reflect.Method.invoke(Method.java:511)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760)
10-24 11:25:45.580: E/AndroidRuntime(29194):    at dalvik.system.NativeStart.main(Native Method)

Loading code:

public void loadPhotoList(){

    Cursor f = db.rawQuery("select * from stationphotos where StationObjectID =  '"+ checkStationObjectID + "'", null);  
    final ArrayList<String> mHelperNames= new ArrayList<String>();

            if(f.getCount() != 0) {
              f.moveToFirst();

                f.moveToFirst();
                while(!f.isAfterLast()) {
                    mHelperNames.add(f.getString(f.getColumnIndex("FilePath")));
                    f.moveToNext();
                }
            }
     f.close();
     final String [] nameStrings = new String [mHelperNames.size()];

     for(int i=0; i<mHelperNames.size(); i++)
        nameStrings[i] = mHelperNames.get(i).toString();


    AlertDialog.Builder builder = new AlertDialog.Builder(this);

    builder.setTitle("Select Picture");
    builder.setItems(nameStrings, new DialogInterface.OnClickListener() {

       public void onClick(DialogInterface dialog, int item) {

          loadPhoto(mHelperNames.get(item).toString());

       }

    });

    AlertDialog alert = builder.create();

    alert.show();

 }


public void loadPhoto(String imagepath){

    Dialog dialog = new Dialog(this);
    dialog.setContentView(R.layout.activity_show_image);
    dialog.setTitle("Image");
    dialog.setCancelable(true);

    ImageView img = (ImageView) dialog.findViewById(R.id.imageView1);
    img.setImageResource(R.drawable.ico_partial);
    Uri imgUri = Uri.parse(imagepath);
    img.setImageURI(imgUri);


    dialog.show();
}

Edit: What i'm using to make it now work:

public static Bitmap decodeSampledBitmapFromFile(String imagePath, int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imagePath, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(imagePath, options);
}
    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        if (width > height) {
            inSampleSize = Math.round((float)height / (float)reqHeight);
        } else {
            inSampleSize = Math.round((float)width / (float)reqWidth);
        }
    }
    return inSampleSize;
}



img.setImageBitmap(decodeSampledBitmapFromFile(imagepath, 500, 500));
like image 385
MissCoder87 Avatar asked Oct 24 '12 10:10

MissCoder87


1 Answers

I have experienced this and I don't know if my answer is best practice or not however...

This is probably your problem:

Uri imgUri = Uri.parse(imagepath);
    img.setImageURI(imgUri);

Heap shot up to 44mb when I loaded the photo.

If you load a large image then you are probably going to run out of memory. Also you will run out of memory if you fail to use decent memory management when loading a series of images.

I used the BitmapFactory to decode the file and used the BitmapFactory.Options to create a new sclaed Bitmap that I then displayed on screen.

The idea is that the BitmapFactory.Options gives you more control over the potential memory that your image could use up. For example there is no need to show a 1920x1080 image at full size on a screen that does not even support those resolutions.

There are some related stackoverflow questions that might help you and in particular: Handling large Bitmaps, which focuses on the BitmapFactory.Options option inJustDecodeBounds.

Finally, I have found this great lightweight library called Aquery. It has a whole raft of methods for handling large files, and so far it does it well. Well worth a look. It uses a similar paradigm to Jquery in respect of web development (hence the name) and introduces a shorter syntax for manipulating Views. The following section of their documentation deals with image loading both locally and from a remote source, including fall back images:

http://code.google.com/p/android-query/wiki/ImageLoading

like image 162
Graham Smith Avatar answered Sep 30 '22 18:09

Graham Smith