Search code examples
androidbitmapfactory

Android BitmapFactory.decodeFile slows down until out of memory


I am processing up to 1200 images. I optimized it to work from 100 images up to 500 with the help of previous questions found here. Now, this is what I have:

   public Bitmap getBitmap(String filepath) {
        boolean done = false;
        int downsampleBy = 2;
        Bitmap bitmap = null;
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filepath, options);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        options.inPreferredConfig = Config.RGB_565;
        while (!done) {
            options.inSampleSize = downsampleBy++;
            try {
                bitmap = BitmapFactory.decodeFile(filepath, options);
                done = true;
            } catch (OutOfMemoryError e) {
                // Ignore.  Try again.
            }
        }
        return bitmap;
    }

This function is called in a loop, and it goes really fast until it hits the 500th image. At this point it slows down, until it finally stops working at around the 600th image.

At this point I don't know how else to optimize it to make it work. What do you think is happening and how can I fix it?

EDIT

            // Decode BItmap considering memory limitations
    public Bitmap getBitmap(String filepath) {
        Bitmap bitmap = null;
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filepath, options);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        options.inPreferredConfig = Config.RGB_565;
        options.inDither = true;
        options.inSampleSize= calculateInSampleSize(options, 160, 120);

        return bitmap = BitmapFactory.decodeFile(filepath, options);
    }

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

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

Made the changes of the accepted answer. Using the function from Google's tutorials to get the correct sample size. Added largeHeap in the manifest and only calling System.gc() once before I loop through all the images.


Solution

  • First of all, you should never expect to catch an Error. Described here: Java documentation An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.

    There is some help about loading bitmaps: Android Developers | Loading large bitmaps

    You can get some more memory by declaring the largeHeap="true" attribute in your Application Manifest.

    And also the System.gc() call might help freeing some unused memory, but I won't really rely on that call.