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?
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:
BufferedInputStream
with a smaller bufferAssetManager.AssetInputStream
as returned by AssetManager.open(...)
(see my answer here on how to use it). Its markSupported()
returns true
.The first alternative might not help much, you'll still have a byte[] array allocated, but at least it is under your control. The second option might turn out to be the most fruitful, if your circumstances allows you to use this approach.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With