Thomas
Thomas

Reputation: 8930

How to get around Android Bitmap out of memory exception?

I would like to display an image as the screen background and since I am having difficulties with image view's scale_type in the xml, I am doing the computations with image ratio and screen dimensions in a function, nothing too complicated

public static Bitmap BitmapToView(Bitmap img, View v) {
    int imgWidth = img.getWidth();
    int imgHeight = img.getHeight();
    int bckWidth = v.getWidth();
    int bckHeight = v.getHeight();
    float ratio1 = (float) bckWidth / imgWidth;
    float ratio2 = (float) bckHeight / imgHeight;
    float maxRatio = Math.max(ratio1, ratio2);
    int newHeight = Math.max((int) (imgHeight * maxRatio), bckHeight);
    int newWidth = Math.max((int) Math.ceil(imgWidth * maxRatio), bckWidth);
    Bitmap tmp_image = Bitmap.createScaledBitmap(img, newWidth, newHeight, true);
    Bitmap ret_image = Bitmap.createBitmap(tmp_image, Math.abs(newWidth - bckWidth)/2, Math.abs(newHeight - bckHeight)/2, bckWidth, bckHeight);
    tmp_image.recycle();
    return ret_image;
}

Options options = new Options();
options.inJustDecodeBounds = false;
Bitmap img = BitmapFactory.decodeFile(imgFilePath, options);
Bitmap newImage = BitmapToView(img, findViewById(R.id.myRelativeLayout);
// RelariveLayout takes up the whole screen ; failing on Samsung Galaxy S4
findViewById(R.id.myRelativeLayout).setBackground(new BitmapDrawable(newimage));

And sometimes I get an out of memory exception I have tried to use .recycle() here and there but then I get "Canvas: trying to use a recycled bitmap"

Any idea ? Thanks

Upvotes: 0

Views: 195

Answers (1)

Xaver Kapeller
Xaver Kapeller

Reputation: 49807

You said you already tried recycle()? But I see you use the same variable for the scaled and not scaled image, have you tried this:

Bitmap image = BitmapFactory.decodeFile("/.../path", options);
...
Bitmap scaledImage = Bitmap.createScaledBitmap(image, newWidth, newHeight, true);
image.recycle(); // <-- Use a new variable for the scaled image so you can recycle the not scaled one

If that doesn't help you please post more of your code and give us more information about what you are trying to do. Otherwise it will be difficult to help you.

EDIT:

This code should crop the small image before scaling it up and should therefore significantly reduce how much memory you use.

Unfortunately I can't test it right now but I'm pretty sure it should work as expected. If there are any problems feel free to ask.

public static Bitmap BitmapToView(Bitmap img, View v) {
    double imgWidth = img.getWidth();
    double imgHeight = img.getHeight();
    double viewWidth = v.getWidth();
    double viewHeight = v.getHeight();

    // Crop image to required aspect ratio

    double imgRatio = imgWidth / imgHeight;
    double viewRatio = viewWidth / viewHeight;

    double cropWidth;
    double cropHeight;
    if (imgRatio > viewRatio) {
        cropWidth = viewRatio * imgHeight;
        cropHeight = imgHeight;
    } else {
        cropHeight = imgWidth / viewRatio;
        cropWidth = imgWidth;
    }

    int cropX = (int) (imgWidth / 2.0 - cropWidth / 2.0);
    int cropY = (int) (imgHeight / 2.0 - cropHeight / 2.0);

    Bitmap croppedBitmap = Bitmap.createBitmap(img, cropX, cropY, (int)cropWidth, (int)cropHeight);
    img.recycle();

    // Scale image to fill view

    Bitmap finalBitmap = Bitmap.createScaledBitmap(croppedBitmap, (int)viewWidth, (int)viewHeight, true);
    croppedBitmap.recycle();
    return finalBitmap;
}

Upvotes: 1

Related Questions