Dinesh Singh
Dinesh Singh

Reputation: 837

App crashes after taking multiple pictures from Android camera

I am developing an application for Android which is supposed to take pictures from camera and use those images as profile pictures for the app. However, the app runs fine for first 3-4 pictures, but when I attempt to take more pictures the app gets crashed. The reason being memory leak.

Here is the code for starting intent of camera:

String fileName = "temp.jpg";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, fileName);
mCapturedImageURI = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);
startActivityForResult(takePictureIntent,RESULT_LOAD_IMAGE_CAMERA);

Here is the code for receiving the intent:

if (requestCode == RESULT_LOAD_IMAGE_CAMERA && resultCode == RESULT_OK ) {
    String[] projection = { MediaStore.Images.Media.DATA};
    Cursor cursor = managedQuery(mCapturedImageURI, projection, null, null, null);
    final int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    String capturedImageFilePath = cursor.getString(column_index_data);
    profilePic.setImageURI(Uri.fromFile(new  File(capturedImageFilePath)));
}

Here is the log:

02-28 18:28:36.727: E/dalvikvm-heap(4081): 9830400-byte external allocation too large for this process.
02-28 18:28:36.727: E/GraphicsJNI(4081): VM won't let us allocate 9830400 bytes
02-28 18:28:36.824: E/AndroidRuntime(4081): FATAL EXCEPTION: main
02-28 18:28:36.824: E/AndroidRuntime(4081): java.lang.OutOfMemoryError: bitmap size    exceeds VM budget
02-28 18:28:36.824: E/AndroidRuntime(4081):     at   android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at   android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:562)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at  android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:426)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.graphics.drawable.Drawable.createFromStream(Drawable.java:657)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.widget.ImageView.resolveUri(ImageView.java:509)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.widget.ImageView.setImageURI(ImageView.java:293)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at com.octanetech.cortes.ProfileActivity.onActivityResult(ProfileActivity.java:596)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.Activity.dispatchActivityResult(Activity.java:3890)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread.deliverResults(ActivityThread.java:3511)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread.handleSendResult(ActivityThread.java:3557)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread.access$2800(ActivityThread.java:125)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2063)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.os.Handler.dispatchMessage(Handler.java:99)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.os.Looper.loop(Looper.java:123)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at android.app.ActivityThread.main(ActivityThread.java:4627)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at java.lang.reflect.Method.invokeNative(Native Method)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at java.lang.reflect.Method.invoke(Method.java:521)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:871)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
02-28 18:28:36.824: E/AndroidRuntime(4081):     at dalvik.system.NativeStart.main(Native Method)

Any help will be highly appreciated.

Upvotes: 1

Views: 4557

Answers (3)

Dinesh Singh
Dinesh Singh

Reputation: 837

Finally I solved the problem myself. The main problem which was causing memory leak is that I was not recycling the bitmap objects. I was just replacing the bitmap object with another bitmap image. Thought the object got replaced by another Bitmap image, still the previous Bitmap image existed in the memory. So, on taking multiple images from Camera, Bitmap images piled up and raised an exception of out-of-memory.

Therefore, I played a trick to recycle(delete) the Bitmap image before assigning a new image to the Bitmap object. I just used

mImageBitmap.recycle();

This flushed away the previous Bitmap image and no memory leak occurred. Hope it helped others as well.

Upvotes: 3

Karan_Rana
Karan_Rana

Reputation: 2823

Try scaling your larger bitmaps using the inSampleSize as follows: Snippet taken from @Fedor's lazy list https://github.com/thest1/LazyList/blob/master/src/com/fedorvlasov/lazylist/ImageLoader.java

public int inSampleSize

If set to a value > 1, requests the decoder to subsample the original image, returning asmaller image to save memory.

//decodes image and scales it to reduce memory consumption
    private Bitmap decodeFile(File f){
        try {
            //decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            FileInputStream stream1=new FileInputStream(f);
            BitmapFactory.decodeStream(stream1,null,o);
            stream1.close();

            //Find the correct scale value. It should be the power of 2.
            final int REQUIRED_SIZE=70;
            int width_tmp=o.outWidth, height_tmp=o.outHeight;
            int scale=1;
            while(true){
                if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                    break;
                width_tmp/=2;
                height_tmp/=2;
                scale*=2;
            }

            //decode with inSampleSize
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            o2.inSampleSize=scale;
            FileInputStream stream2=new FileInputStream(f);
            Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
            stream2.close();
            return bitmap;
        } catch (FileNotFoundException e) {
        } 
        catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

Hope this help you:

Upvotes: 0

MAC
MAC

Reputation: 15847

Replace this line

profilePic.setImageURI(Uri.fromFile(new  File(capturedImageFilePath)));

You are loading images from sdcard directly and it may be large in size that causing memory problem.

Try this

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize=8;      // 1/8 of original image
Bitmap b = BitmapFactory.decodeFile(capturedImageFilePath,options);
profilePic.setImageBitmap(b);

Upvotes: 3

Related Questions