Работа с изображениями может быстро привести к проблемам с производительностью, если не проявлять осторожность. Даже небольшое изображение в сжатом формате, таком как JPG или PNG, может превратиться в большой растровый файл при декодировании для отображения. Если вы неэффективно используете графику, могут возникнуть проблемы с памятью, которые негативно повлияют на производительность вашего приложения и других приложений на устройстве. Следуйте этим рекомендациям, чтобы обеспечить оптимальную производительность вашего приложения.
Используйте библиотеки для загрузки изображений.
Вы можете повысить эффективность своего приложения, используя библиотеки для загрузки изображений, такие как Coil (для проектов, ориентированных на Kotlin) или Glide (для проектов на Java). Эти библиотеки сокращают потребление памяти вашим приложением за счет кэширования изображений, уменьшения разрешения графики при необходимости и повторного использования графических объектов.
Уменьшение разрешения изображений
Убедитесь, что используете подходящий размер изображения для ваших нужд. Следует избегать загрузки большого изображения с высоким разрешением в небольшой контейнер (например, миниатюру). Вместо этого используйте уменьшение разрешения, чтобы масштабировать изображение перед декодированием в память.
понижение разрешения на стороне клиента
Библиотеки для загрузки изображений, такие как Coil и Glide, автоматически выполняют понижение разрешения. Вы можете настроить их стратегии понижения разрешения с помощью ImageLoader (для Coil) или DownsampleStrategy (для Glide). Если вы работаете с растровыми изображениями вручную, вы можете использовать inSampleSize для декодирования уменьшенной версии. Для безопасного выполнения этой операции сначала следует установить inJustDecodeBounds в true , чтобы считывать размеры изображения без выделения памяти, вычислить размер выборки, установить inSampleSize равным этому значению, установить inJustDecodeBounds в false , а затем декодировать изображение.
Предпочтительно изменение размера на стороне сервера.
По возможности, запрашивайте необходимые размеры изображений непосредственно с вашего серверного приложения. Это снижает нагрузку на сеть и объем дискового кэша, а также уменьшает потребление памяти за счет избежания накладных расходов на изменение размера изображений на устройстве.
Вы можете настроить библиотеки для динамического добавления размера целевого представления к URL-адресу изображения. Например, Coil позволяет это делать с помощью пользовательских перехватчиков, а Glide поддерживает это с помощью пользовательских загрузчиков моделей (таких как BaseGlideUrlLoader ).
Избегайте нестандартных размеров макета.
Для эффективного уменьшения разрешения изображений (на стороне клиента или сервера) программам загрузки изображений необходимо знать целевой размер до выполнения запроса.
Избегайте использования wrapContentSize или оставления размеров без ограничений в компонуемых объектах, загружающих удаленные изображения. Если эти библиотеки не могут определить целевые границы, они переключаются на загрузку исходного изображения в полном размере. Это может привести к загрузке изображения значительно большего размера, чем необходимо, что увеличит использование памяти и задержку.
Вместо этого задайте явные размеры для вашего составного изображения (например, с помощью Modifier.size ) или определите соотношение сторон. Это позволит механизму компоновки заранее вычислить точное целевое значение в пикселях, которое затем загрузчик изображений сможет использовать для запроса и декодирования ресурса правильного размера.
Предоставьте альтернативные ресурсы для экранов разных размеров.
Если вы поставляете изображения вместе с приложением, рассмотрите возможность предоставления изображений разных размеров для разных разрешений устройств. Это поможет уменьшить размер загружаемого приложения на устройствах и повысить производительность, поскольку на устройствах с более низким разрешением будет загружаться изображение с более низким разрешением. Для получения дополнительной информации о предоставлении альтернативных растровых изображений для разных размеров устройств ознакомьтесь с документацией по альтернативным растровым изображениям .
Не приклеивайте прокладку напрямую.
Иногда может потребоваться добавить отступы к изображению. Например, вам может понадобиться, чтобы изображение было окружено прозрачной рамкой для эффекта «letterboxing» (черных полос по краям). В таких ситуациях не следует добавлять отступы непосредственно к изображению, изменяя его размеры. Вместо этого оставьте размеры изображения как есть и отрегулируйте его положение на экране с помощью InsetDrawable . В качестве альтернативы, вы можете добавить отступы в Composable или View, содержащий изображение.
Выберите правильный формат пикселей.
Сбалансируйте использование памяти и качество, выбрав правильный формат пикселей. Используйте RGB_565 если прозрачность не требуется; этот формат использует вдвое меньше памяти, чем формат ARGB_8888 по умолчанию.
В Glide это можно настроить с помощью DecodeFormat . В Coil можно использовать свойство bitmapConfig .
По возможности используйте векторы.
Для изображений, состоящих из геометрических фигур, векторная графика значительно меньше растрового изображения и плавно масштабируется при любой плотности пикселей. При необходимости используйте такие элементы, как ShapeDrawable для представления графики.
По возможности, используйте и освобождайте растровые изображения повторно.
Большие графические файлы могут занимать много памяти. Чтобы уменьшить их влияние, следует по возможности освобождать или повторно использовать графические объекты.
Если вы используете библиотеку для загрузки изображений, убедитесь, что вы освобождаете растровые изображения в управляемом пуле библиотеки, когда они вам больше не нужны. Библиотека сможет повторно использовать объекты при необходимости и сохранит буфер памяти, доступный для будущих нужд.
При ручном управлении графикой следует освобождать растровые изображения после завершения работы с ними, вызывая метод Bitmap.recycle и немедленно удаляя ссылку на Bitmap , вместо того чтобы полагаться на сборку мусора.
Другие советы и рекомендации
В этом разделе перечислены еще несколько способов улучшить производительность вашего приложения при обработке графики.
Не упаковывайте большие изображения вместе с файлами AAB/APK.
Одной из главных причин большого размера загружаемых приложений являются графические файлы, упакованные в AAB- или APK-архивы. Используйте инструмент анализа APK , чтобы убедиться, что вы не упаковываете файлы изображений большего размера, чем необходимо. Уменьшите размер файлов или рассмотрите возможность размещения изображений на сервере и загрузки их только при необходимости.
Найти избыточные растровые изображения
Если у вас несколько копий одного и того же изображения, это приводит к нерациональному использованию памяти. Вы можете использовать профилировщик Android Studio для выявления избыточных графических элементов. Используйте анализатор дампа кучи , чтобы создать дамп кучи, и отфильтруйте результаты, выбрав параметр « дублирующиеся растровые изображения» .
При использовании ImageBitmap вызовите метод prepareToDraw перед началом отрисовки.
При использовании ImageBitmap для начала процесса загрузки текстуры на графический процессор вызовите ImageBitmap#prepareToDraw() перед фактической отрисовкой. Это помогает графическому процессору подготовить текстуру и повысить производительность отображения изображения на экране. Большинство библиотек для загрузки изображений уже выполняют эту оптимизацию, но если вы работаете с классом ImageBitmap самостоятельно, это следует учитывать.
Вместо Painter лучше передавать в качестве параметров объект DrawableRes Int или URL.
Из-за сложностей работы с изображениями (например, написание функции equals для Bitmaps потребовало бы больших вычислительных затрат), API Painter явно не помечен как стабильный с помощью аннотации @Stable . Нестабильные классы могут привести к ненужным перекомпозициям, поскольку компилятору будет сложно определить, изменились ли данные.
Поэтому мы рекомендуем передавать в качестве параметров вашего составного объекта URL-адрес или идентификатор ресурса изображения, а не объект Painter .
// Prefer this:
@Composable
fun MyImage(url: String) {
}
// Over this:
@Composable
fun MyImage(painter: Painter) {
}
Рекомендуем вам
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- ImageBitmap против ImageVector {:#bitmap-vs-vector}
- Сохранение состояния пользовательского интерфейса в Compose
- Фазы композиции Jetpack