Reputation: 837
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
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
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
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