Управление памятью при работе с изображениями

В дополнение к предыдущему уроку, мы поговорим о том, как облегчить работу сборщика мусора и повторно использовать изображения. Что конкретно делать зависит от версий Android, которые вы планируете поддерживать. Приложение BitmapFun, которое описано в этом уроке, показывает, как создавать эффективные приложения, работающие в различных версиях Android.

Работа с памятью эволюционировала следующим образом:

  • В Android 2.2 (API 8) и ниже, при работе сборщика мусора поток останавливался. Это могло служить причиной снижения производительности. В Android 2.3 добавлен другой сборщик мусора, который предполагает, что память будет освобождена вскоре после того, как изображение стало недоступным.
  • В Android 2.3.3 (API 10) и ниже, пиксельные данные изображения хранились в нативной памяти отдельно от самого изображения, которое хранилось в памяти виртуальное машины Dalvik. Пиксельные данные в нативной памяти не освобождаются предсказуемым образом, что потенциально может привести к исчерпанию памяти и краху приложения. Начиная с Android 3.0 пиксельные данные хранятся в памяти виртуальной машины вместе с самим изображением.

Далее мы рассмотрим как оптимизировать работу с память в различных версиях Android.

Управление памятью в Android 2.3.3 и ниже

В Android 2.3.3 (API 10) и ниже, рекомендуется использовать метод recycle(). Если вы показываете большое количество графических данных в приложении, вы вероятно столкнетесь с ошибками OutOfMemoryError. Метод recycle() позволяет приводить память в чувство, насколько это возможно.

Внимание: вы должны использовать метод recycle() только если уверены, что изображение больше не используется. Если вы вызовите метод и после этого попытаетесь отобразить картинку, вы получите ошибку "Canvas: trying to use a recycled bitmap".

Далее приведен пример вызова recycle(). Используется подсчет ссылок (в переменных mDisplayRefCount и mCacheRefCount) для отслеживания статуса изображения: оно отображается на экране или сохранено в кэше. Данный код удаляет изображение, если выполняются следующие условия:

  • Количество ссылок в обоих переменных равно нулю
  • Объект изображения не равен null и еще не удален

Управление память в Android 3.0 и выше

В Android 3.0(API 11) появилась опция BitmapFactory.Options.inBitmap. Если опция включена, методы декодирования попытаются использовать существующий объект при загрузке данных. Это означает, что память с загруженными изображениями используется повторно, что в результате повышает производительность и убирает лишние операции выделения и освобождения памяти. Однако, существуют определенные ограничения в использовании inBitmap. В частности до Android 4.4(API 19) поддерживаются только изображения с эквивалентным размером. Подробности в документации по опции inBitmap.

Сохранение изображений для повторного использования

В следующем примере показано, как сохранить существующее изображение для возможно использования в будущем. При запуске на Android 3.0 и выше и использовании LruCache, мягкие ссылки на изображение размещены в объекте типа HashSet, чтобы использовать его совместно с inBitmap:

Использование существующего изображения

При работе приложения, методы декодирования проверяют существование изображений, которые они могут использовать. Например:

В следующем примере приведен метод addInBitmapOptions(). Он ищет существующие изображения, чтобы установить их значение в inBitmap. Заметьте, что этот метод устанавливает значение inBitmap только если находит подходящее совпадение (ваш код никогда не должен предполагать, что совпадение будет найдено):

И наконец последний метод, который определяет, удовлетворяет ли кандидат размерам, чтобы использоваться в inBitmap:

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