-1

I am developing an android app that decodes a jpeg file and draws the bitmap on the canvas with canvas.drawBitmap(). I am decoding the jpeg into a bitmap using BitmapFactory.decodeStream().

Everything works fine when I work with images of resolutions such as 2560x1536. Recently, I did a stress test and tried to open a really big jpeg of resolution 5400x3600. My app crashed with error "java.lang.OutOfMemoryError".

Here is the stack trace:

java.lang.OutOfMemoryError
    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
    at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:720)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:696)
    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:734)
    ...

It is understandable since that is a large image and a decoded bitmap uses a lot of memory.

However, what I am trying to understand is on the same phone, if I use the gallery app, the gallery app can display the same big image without any problems.

On the same phone, if I also try to open the same big image with some picture editing tool that I think should also decode the jpeg into a bitmap, then everything works fine as well. It takes a bit more time for those apps to display the image, but the image is loaded and drawn on the screen.

I am trying to understand what I could be doing wrong and differently compared to those other apps ?

RichardT
  • 325
  • 1
  • 10

2 Answers2

0

First, you need to set

 android:largeHeap="true"

in Android manifest. Then it's illusion that same size image is shown in systems gallery. Actually, each and every library or gallery resize image according to available size on screen by maintaining Aspect Ratio of Images and quality.

So you need to resize your image before getting big images form system.

Loading Large Bitmaps Efficiently

Read Bitmap Dimensions and Type

The BitmapFactory class provides several decoding methods (decodeByteArray(), decodeFile(), decodeResource(), etc.) for creating a Bitmap from various sources. Choose the most appropriate decode method based on your image data source. These methods attempt to allocate memory for the constructed bitmap and therefore can easily result in an OutOfMemory exception. Each type of decode method has additional signatures that let you specify decoding options via the BitmapFactory.Options class. Setting the inJustDecodeBounds property to true while decoding avoids memory allocation, returning null for the bitmap object but setting outWidth, outHeight and outMimeType. This technique allows you to read the dimensions and type of the image data prior to construction (and memory allocation) of the bitmap.

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

To avoid java.lang.OutOfMemory exceptions, check the dimensions of a bitmap before decoding it, unless you absolutely trust the source to provide you with predictably sized image data that comfortably fits within the available memory.

Load a Scaled Down Version into Memory Now that the image dimensions are known, they can be used to decide if the full image should be loaded into memory or if a subsampled version should be loaded instead. Here are some factors to consider:

Estimated memory usage of loading the full image in memory. Amount of memory you are willing to commit to loading this image given any other memory requirements of your application. Dimensions of the target ImageView or UI component that the image is to be loaded into. Screen size and density of the current device.

See Link

Chetan Joshi
  • 5,279
  • 4
  • 24
  • 33
0

OutOfMemoryError

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector .

Make sure , Added

<application
    android:largeHeap="true"
   >

To avoid java.lang.OutOfMemory exceptions, check the dimensions of a bitmap before decoding it, unless you absolutely trust the source to provide you with predictably sized image data that comfortably fits within the available memory.

Read Loading Large Bitmaps Efficiently .

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 below code:

imgOBJ.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

You can check Solve java.lang.OutOfMemoryError trouble in Android

IntelliJ Amiya
  • 70,230
  • 14
  • 154
  • 181