Эффективная загрузка больших растровых изображений

Изображения имеют разные формы и размеры. В большинстве случаев они больше, чем требует типовой пользовательский интерфейс. Например, приложение Галерея показывает фотографии, сделанные пользователем на встроенную камеру, которые обычно имеют разрешение выше, чем разрешение экрана устройства.

Учитывая, что объем памяти ограничен, в идеале нужно загружать в память изображения с меньшим разрешением. Такие версии изображений должны подстраиваться под размер компонента, в котором они отображаются. Картинки с большим разрешением не дают видимых преимуществ, но занимают драгоценную память и требуют лишней производительности для вычислений на лету.

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

Узнаем тип и разрешение изображения

Класс BitmapFactory предоставляет несколько методов декодирования (decodeByteArray(), decodeFile(), decodeResource(), и.т.д) для создания объекта типа Bitmap из различных ресурсов. Выберите соответствующий метод, основываясь на вашем источнике данных. Методы пытаются выделить память для построения растрового изображения и запросто могут вызвать исключение OutOfMemory. Каждый метод имеет дополнительные сигнатуры, которые позволяют задать параметры декодирования с помощью класса BitmapFactory.Options. Установите свойство inJustDecodeBounds в значение true. Тогда память не будет выделяться, а объект будет равен null, но будут установлены свойства outWidth, outHeight и outMimeType. Это позволит узнать разрешение и тип графических данных до создания объекта Bitmap (и соответственно до выделения памяти).

Чтобы предотвратить исключение java.lang.OutOfMemory, проверьте разрешение изображения до его декодирования, чтобы убедиться, что предоставленные данные легко поместятся в доступную память.

Загрузка уменьшенной версии в память

Теперь разрешение картинки известно и может быть использовано для принятия решения: загрузить в память полноразмерную версию картинки или ее уменьшенную версию. Вот некоторые факторы, которые нужно учитывать:

  • Расчетное потребление памяти при загрузке полной версии.
  • Количество памяти, которое вы готовы потратить на изображение, учитывая общее потребление памяти приложением.
  • Разрешение компонента ImageView, который будет отображать загруженные данные.
  • Размер и плотность точек экрана на текущем устройстве.

Например, не стоит загружать изображение размером 1024x768px в память, если в конечном счете оно будет показано в ImageView размером 128×96 пикселей в качестве иконки.

Чтобы декодер загрузил в память уменьшенную версию, установите свойство inSampleSize в объекте BitmapFactory.Options. Например, изображение размером 2048×1536 пикселей, которое обрабатывается с опцией inSampleSize равной 4, уменьшится приблизительно до 512×384 пикселей. В памяти оно займет 0.75Мб вместо 12Мб для полноразмерной картинки (при конфигурации ARGB_8888). Далее приведен метод расчета размера образца, равного степени двойки, на основе необходимой ширины и высоты:

Примечание: для расчета используется значение степени двойки, поскольку декодер использует конечное значение, округленное до степени двойки, согласно документации inSampleSize.

Чтобы использовать описанный метод, сначала вызываем декодер с опцией inJustDecodeBounds равной true для получения параметров изображения. Затем повторно вызываем декодер, используя новое значение inSampleSize и установив inJustDecodeBounds в значение false:

Метод позволяет очень просто загружать произвольные изображения в ImageView размером 100x100px, как показано ниже:

Вы можете подобным образом декодировать изображения из любых источников, применив соответствующий метод BitmapFactory.decode*.

Добавить комментарий