BitmapFactory.Options.inTempStorage字段

fhu*_*cho 12 android bitmap

我有一个通过在Canvas上绘制位图图块实现的自定义离线地图.我正在尝试消除对象创建以减少GC运行,从而使地图滚动更顺畅.我在Allocation Tracker中看到BitmapFactory.decodeFile(...)总是创建byte [16400]对象.我认为在BitmapFactory.Options中设置inTempStorage字段会改变:

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);
Run Code Online (Sandbox Code Playgroud)

但即使使用这段代码,我仍然会看到decodeFile创建了byte []数组.所以有什么问题?

Mar*_*lts 17

简而言之,问题是当你使用BitmapFactory.decodeFile(String, Options)Android时会分配一个16 kB BufferedInputStream,独立于options.inTempStorage.

更详细一点:BitmapFactory.decodeFile(String, Options)是一个BitmapFactory.decodeStream(InputStream, Rect, Options)使用a 的包装器FileInputStream.在执行中BitmapFactory.decodeStream(InputStream, Rect, Options),有这样的代码:

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);
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

由于FileInputStreammarkSupported()回报率false,这意味着独立的 options.inTempStorage,一个BufferedInputStream具有16 KB缓冲区会为您创建,如果你使用BitmapFactory.decodeFile(String, Options).

为了避免这种16 kB的分配,你可以尝试BitmapFactory.decodeStream(InputStream, Rect, Options)直接使用InputStreamfor markSupported()返回true.

我可以想到两个值得研究的替代方案:

  1. 使用BufferedInputStream较小的缓冲区自己使用
  2. 使用AssetManager.AssetInputStream返回AssetManager.open(...)(参见我在这里的答案如何使用它).它的markSupported()回报true.

第一种选择可能没什么用,你仍然会分配一个byte []数组,但至少它在你的控制之下.如果您的情况允许您使用此方法,第二个选项可能会变得最有成效.