Alex Rivera | Logout

BitmapFactory.Options.inTempStorage field

Asked 2011-04-02T13:53:14.983
12

I have a custom offline map implemented by drawing Bitmap tiles on Canvas. I'm trying to eliminate object creations to reduce GC runs and therefore make the map scrolling smoother. I see in Allocation Tracker that BitmapFactory.decodeFile(...) always creates byte[16400] object. I thought that setting inTempStorage field of BitmapFactory.Options would change that:

byte[] buffer = new byte[16*1024];
// ...
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.RGB_565;
options.inTempStorage = buffer;
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);

But even with this code I still see decodeFile creating the byte[] array. So what's the problem?

Edit
Report

1 Answer

17

In short, the problem is that when you use BitmapFactory.decodeFile(String, Options) then Android will allocate a 16 kB BufferedInputStream, independently of options.inTempStorage.

To be more elaborate: BitmapFactory.decodeFile(String, Options) is a wrapper around BitmapFactory.decodeStream(InputStream, Rect, Options) that uses a FileInputStream. In the implementation of BitmapFactory.decodeStream(InputStream, Rect, Options), there is this code:

public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
    // ...

    // we need mark/reset to work properly
    if (!is.markSupported()) {
        is = new BufferedInputStream(is, 16 * 1024);
    }

    // ...
}

Since FileInputStream's markSupported() returns false, that means that independently of options.inTempStorage, a BufferedInputStream with a 16 kB buffer will be created for you if you use BitmapFactory.decodeFile(String, Options).

To avoid this 16 kB allocation, you could try to use BitmapFactory.decodeStream(InputStream, Rect, Options) directly with an InputStream for which markSupported() returns true.

I can think of two alternatives that could be worth looking into:

  1. Use your own BufferedInputStream with a smaller buffer
  2. Use AssetManager.AssetInputStream as returned by AssetManager.open(...) (see my answer answered 2011-11-14T11:13:43.203

Your Answer