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 开发者_StackOverflow社区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:
- Use your own
BufferedInputStream
with a smaller buffer - Use
AssetManager.AssetInputStream
as returned byAssetManager.open(...)
(see my answer here on how to use it). ItsmarkSupported()
returnstrue
.
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.
精彩评论