Подтвердить что ты не робот

Поле BitmapFactory.Options.inTempStorage

У меня есть настраиваемая автономная карта, реализованная путем рисования растровых изображений на Canvas. Я пытаюсь устранить создание объектов, чтобы уменьшить количество циклов GC и, следовательно, сделать плавную прокрутку карты более плавной. Я вижу в Allocation Tracker, что BitmapFactory.decodeFile(...) всегда создает объект byte [16400]. Я думал, что установка поля inTempStorage в BitmapFactory.Options изменит это:

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

Но даже с этим кодом я все еще вижу decodeFile, создающий массив byte []. Итак, в чем проблема?

4b9b3361

Ответ 1

Вкратце, проблема в том, что при использовании BitmapFactory.decodeFile(String, Options) тогда Android будет выделять 16 kB BufferedInputStream, независимо от options.inTempStorage.

Чтобы быть более сложным: BitmapFactory.decodeFile(String, Options) является оберткой вокруг BitmapFactory.decodeStream(InputStream, Rect, Options), которая использует 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);
    }

    // ...
}

Так как FileInputStream markSupported() возвращает false, это означает, что независимо от options.inTempStorage для вас будет создан BufferedInputStream с буфером 16 kB, если вы используете BitmapFactory.decodeFile(String, Options).

Чтобы избежать этого выделения 16 kB, вы можете попробовать использовать BitmapFactory.decodeStream(InputStream, Rect, Options) напрямую с InputStream, для которого markSupported() возвращает true.

Я могу подумать о двух альтернативах, которые можно было бы рассмотреть:

  • Используйте свой собственный BufferedInputStream с меньшим буфером
  • Используйте AssetManager.AssetInputStream как возвращаемый AssetManager.open(...) (см. мой ответ здесь о том, как его использовать). Его markSupported() возвращает true.

Первый вариант может не помочь, у вас все равно будет выделен массив byte [], но по крайней мере он находится под вашим контролем. Второй вариант может оказаться самым плодотворным, если ваши обстоятельства позволяют использовать этот подход.