views:

1888

answers:

6

Getting an Exception in the BitmapFactory. Not sure what is the issue. (Well I can guess the issue, but not sure why its happening)

ERROR/AndroidRuntime(7906): java.lang.OutOfMemoryError: bitmap size exceeds VM budget

ERROR/AndroidRuntime(7906):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:295)

My code is pretty straight forward. I defined an XML layout w/ a default image. I try to load a bm on the SDCard (if present - it is). If not it shows the default image. Anyway.. Here is code :

public class showpicture extends Activity {
  public void onCreate(Bundle savedInstanceState) {

         /** Remove menu/status bar **/
         requestWindowFeature(Window.FEATURE_NO_TITLE);
         final Window win = getWindow();   
         win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);

            Bitmap bm;
         super.onCreate(savedInstanceState);
         setContentView(R.layout.showpicture);
            try {
         ImageView mImageButton = (ImageView)findViewById(R.id.displayPicture);
         bm = Bitmap.createScaledBitmap(BitmapFactory.decodeFile("/sdcard/dcim/Camera/20091018203339743.jpg"),100, 100, true);
         parkImageButton.setImageBitmap(bm);
         }
         catch (IllegalArgumentException ex) {
          Log.d("MYAPP",ex.getMessage());
         } 
            catch (IllegalStateException ex) {

It fails on the bm=Bitmap.createScaledBitmap any thoughts? I did some research on the forums, and it pointed to this post I just don't know why it is not working. Any help would be great! Thanks,

Chris.

+1  A: 

I think it is - what it it say it is. Your image is too big and since it is loaded in the stream when the memory is exhausted the exception is thrown. It's not even the question on how much memory you have overall but how much your particular Activity has available.

DroidIn.net
The image is from a G1 phone camera. Image size was 2048x1536 apx 1.01MB
Chrispix
That's shoulf be OK but then, again - it's not the cumulative memory that counts but how much was allocated by system to your specific task. Can you verify that your code works with say 500K or 50K?
DroidIn.net
A: 

I ended up resizing the bitmap using the following code which seems to have resolved the issue.

BitmapFactory.Options options=new BitmapFactory.Options(); options.inSampleSize = 8; Bitmap preview_bitmap=BitmapFactory.decodeFile(mPathName, options);

Chrispix
+2  A: 

Make sure to guard your bitmap creation from out of memory errors! With most platforms, android doesn't have much memory to play with and it runs out quickly with bitmaps. Also, make sure to manually recycle your bitmaps as much as possible, I've noticed that the garbage collection can be rather slow.

try{            
  Bitmap myFragileBitmap = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888);
}
catch(IllegalArgumentException e){
  Log.e(TAG,"Illegal argument exception.");
}
catch(OutOfMemoryError e){
  Log.e(TAG,"Out of memory error :(");
}
Ralphleon
Best way to do the GC? myFragileBitmap=null?
Chrispix
Doesn't always seem to do it, for some reason I normally set it to null after recycling however... I assume there exists some skia magic for bitmap clearing...
Ralphleon
+2  A: 

inSampleSize is a good hint. But a fixed value often doesn't work fine, since large bitmaps from files usually are user files, which can vary from tiny thumbnails to 12MP images from the digicam.

Here's a quick and dirty loading routine. I know there's room for improvement, like a nicer coded loop, using powers of 2 for faster decoding, and so on. But it's a working start...

public static Bitmap loadResizedBitmap( String filename, int width, int height, boolean exact ) {
    Bitmap bitmap = null;
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile( filename, options );
    if ( options.outHeight > 0 && options.outWidth > 0 ) {
        options.inJustDecodeBounds = false;
        options.inSampleSize = 2;
        while (    options.outWidth  / options.inSampleSize > width
                && options.outHeight / options.inSampleSize > height ) {
            options.inSampleSize++;
        }
        options.inSampleSize--;

        bitmap = BitmapFactory.decodeFile( filename, options );
        if ( bitmap != null && exact ) {
            bitmap = Bitmap.createScaledBitmap( bitmap, width, height, false );
        }
    }
    return bitmap;
}

Btw, in the newer APIs there are also lots of BitmapFactory.Option's for fitting the image to screen DPIs, but I'm not sure whether they really simplify anything. Using android.util.DisplayMetrics.density or simply a fixed size for less memory consumption seem to work better imho.

M. Schenk
A: 

Hi... Have you checked the DDMS? With what I have been encountering, it's probably not the size of the images, because Android seems to handle large images pretty well. If you trace the heap with DDMS you may find that you happen to have a lot of free memory. You can "expand" your heap by adding this

static { @SuppressWarnings("unused")
byte dummy[] = new byte[ 8*1024*1024 ]; }    

to your code, to force the heap to expand. It may make it a bit less frequent. Unfortunately, with the exception it claims that it can't allocate some amount of bytes. Say 1M. If you take a look at the "free" line you will see that the largest block is >> 1M. There is something strange there that I can't figure out. It is not related even to the speed of swiping images. I saw in some thread that you can call "recycle" or so for bitmaps. I still don't see why it should help if the heap size is way above the taken size.

Thanks S.

Meymann