1

I'm having an OutOfMemoryError in my VSD220 (It's a 22" Android based All in one)

for (ImageView img : listImages) {
            System.gc();

            Bitmap myBitmap = BitmapFactory.decodeFile(path);
            img.setImageBitmap(myBitmap);
            img.setOnClickListener(this);
        }

I really don't know what to do, because this image is below the maximum resolution. The image size is something about (1000x1000), and the display it's 1920x1080.

Any help? (That foreach cycle is for about 20 elements, it gots broken after 6, or 7 loops..)

Thanks a lot.

Ezequiel.

Eze Barnes
  • 57
  • 2
  • 8
  • I don't agree with marking this as a duplicate. In this question the same image is repeatedly loaded in a loop. Even if the image would be very small you'd get an out of memory error if the number of iterations are high enough. – britzl May 22 '13 at 17:52

2 Answers2

1

You should take a look at the training docs for Managing Bitmap Memory. Depending on your OS version, you could use different techniques to allow you to manage more Bitmaps, but you'll probably have to change your code anyway.

In particular, you're probably going to have to use an amended version of the code in "Load a Scaled Down Version into Memory", but I at least have found this section to be particularly useful:

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) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }

    return inSampleSize;
}



public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {

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

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

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

This method makes it easy to load a bitmap of arbitrarily large size into an ImageView that displays a 100x100 pixel thumbnail, as shown in the following example code:

mImageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
DigCamara
  • 5,540
  • 4
  • 36
  • 47
0

Are you really sure you want to load the same Bitmap 20 times? Don't you want to load it once and set it inside the loop.

Still, loading a 1000x1000 pixel image is not guaranteed to work, regardless of screen resolution. Remember that a 1000x1000 pixel image takes up 1000x1000x4 bytes =~4MB (if you load it as ARGB_8888). If your heap memory is fragmented/too small you may not have enough space to load the bitmap. You may want to look into the BitmapFactory.Options class and experiment with inPreferredConfig and inSampleSize

I would suggest that you either use the suggestion by DigCamara and decide on a size and load a downsampled image of nearly that size (I say nearly because you won't get the exact size using that technique) or that you try to load the full size image and then recursively increase the sample size (by factors of two for best result) until you either reach a max sample size or the image is loaded:

/**
 * Load a bitmap from a stream using a specific pixel configuration. If the image is too
 * large (ie causes an OutOfMemoryError situation) the method will iteratively try to
 * increase sample size up to a defined maximum sample size. The sample size will be doubled
 * each try since this it is recommended that the sample size should be a factor of two
 */
public Bitmap getAsBitmap(InputStream in, BitmapFactory.Config config, int maxDownsampling) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 1;   
    options.inPreferredConfig = config;
    Bitmap bitmap = null;
    // repeatedly try to the load the bitmap until successful or until max downsampling has been reached
    while(bitmap == null && options.inSampleSize <= maxDownsampling) {
        try {
            bitmap = BitmapFactory.decodeStream(in, null, options);
            if(bitmap == null) {
                // not sure if there's a point in continuing, might be better to exit early
                options.inSampleSize *= 2;
            }
        }
        catch(Exception e) {
            // exit early if we catch an exception, for instance an IOException
            break;
        }
        catch(OutOfMemoryError error) {
            // double the sample size, thus reducing the memory needed by 50%
            options.inSampleSize *= 2;
        }
    }
    return bitmap;
}
britzl
  • 10,132
  • 7
  • 41
  • 38
  • Sorry, I don't want to load the same image 20 times, I wanted to simplify the example, my real code consist of an array of paths. So the image is not the same, but the sizes are. I'm trying your answers right now guys. I will comment again after this. Thank you very much!! – Eze Barnes May 23 '13 at 15:55
  • Thank you both very much. It worked for this thumbnails, now I have to display a full screen image (1920x1024 in this case), and make a gallery of them. I will try to do this reading the android bitmap section! http://developer.android.com/training/displaying-bitmaps/index.html – Eze Barnes May 23 '13 at 16:32