Оптимизация памяти имеет решающее значение для обеспечения бесперебойной работы, предотвращения сбоев приложений, а также поддержания стабильности системы и работоспособности платформы. Хотя использование памяти необходимо отслеживать и оптимизировать в каждом приложении, контент-приложения для телевизионных устройств имеют особые проблемы, которые отличаются от типичных приложений Android для портативных устройств.
Высокое потребление памяти может привести к проблемам с поведением приложений и системы, в том числе:
- Само приложение может работать медленно, тормозить или, в худшем случае, выйти из строя.
- Видимые пользователю системные службы (регулятор громкости, панель настроек изображения, голосовой помощник и т. д.) работают очень медленно или могут вообще не работать.
- Компоненты системы могут выйти из строя; затем эти компоненты перезапускаются, вызывая всплески жесткой конкуренции за ресурсы и напрямую влияя на приложение переднего плана.
- Переход к панели запуска может быть значительно задержан, и приложение на переднем плане может перестать отвечать на запросы до завершения перехода.
- Система может войти в ситуацию прямого восстановления , временно приостанавливая выполнение потоков в ожидании выделения памяти. Это может произойти с любым потоком, например с основным потоком или потоками, связанными с кодеком, что может привести к потере кадров аудио и видео, а также сбоям пользовательского интерфейса.
Рекомендации по использованию памяти на ТВ-устройствах
Телевизионные устройства обычно имеют значительно меньше памяти, чем телефоны или планшеты. Например, конфигурация, которую мы видим на телевизоре, — это 1 ГБ ОЗУ и разрешение видео 1080p . В то же время большинство телевизионных приложений имеют схожие функции; следовательно, аналогичная реализация и общие проблемы. Эти две ситуации представляют проблемы, не встречающиеся в других типах устройств и приложениях:
- Приложения Media TV обычно состоят как из изображений с сеткой, так и из полноэкранных фоновых изображений , которые требуют загрузки большого количества изображений в память за короткий период времени.
- Телевизионные приложения воспроизводят мультимедийные потоки , для которых требуется выделить определенный объем памяти для воспроизведения видео и аудио, а также требуются значительные медиа-буферы для обеспечения плавного воспроизведения.
- Дополнительные мультимедийные функции (поиск, смена эпизодов, смена звуковой дорожки и т. д.) могут потребовать дополнительной нагрузки на память, если они не реализованы должным образом.
Общие сведения о телевизионных устройствах
В этом руководстве основное внимание уделяется использованию памяти приложений и целевым показателям памяти для устройств с низким объемом оперативной памяти.
При выборе телевизионных устройств учитывайте следующие характеристики:
- Память устройства : объем оперативной памяти (ОЗУ), установленной в устройстве.
- Разрешение пользовательского интерфейса устройства : разрешение, которое устройство использует для отображения пользовательского интерфейса ОС и приложений; обычно это ниже разрешения видео устройства.
- Разрешение видео : максимальное разрешение, с которым устройство может воспроизводить видео.
Это приводит к категоризации различных типов устройств и тому, как они должны использовать память.
Обзор телевизионных устройств
Память устройства | Разрешение видео устройства | Разрешение пользовательского интерфейса устройства | isLowRAMDevice() |
---|---|---|---|
1 ГБ | 1080p | 720p | Да |
1,5 ГБ | 2160p | 1080p | Да |
≥1,5 ГБ | 1080p | 720p или 1080p | Нет* |
≥2 ГБ | 2160p | 1080p | Нет* |
ТВ-устройства с малым объемом оперативной памяти
Эти устройства находятся в ситуации с ограниченной памятью и сообщат ActivityManager.isLowRAMDevice()
значение true. Приложениям, работающим на ТВ-устройствах с малым объемом оперативной памяти, необходимо реализовать дополнительные меры управления памятью .
Мы считаем, что к этой категории относятся устройства со следующими характеристиками:
- Устройства с объемом памяти 1 ГБ : 1 ГБ ОЗУ, разрешение пользовательского интерфейса 720p/HD (1280x720), разрешение видео 1080p/FullHD (1920x1080).
- Устройства 1,5 ГБ : 1,5 ГБ ОЗУ, разрешение пользовательского интерфейса 1080p/FullHD (1920x1080), разрешение видео 2160p/UltraHD/4K (3840x2160)
- Другие ситуации, в которых OEM-производитель определил флаг
ActivityManager.isLowRAMDevice()
из-за дополнительных ограничений памяти.
Обычные ТВ-устройства
Эти устройства не страдают от такой значительной нехватки памяти. Мы считаем, что эти устройства имеют следующие характеристики:
- ≥1,5 ГБ ОЗУ, пользовательский интерфейс 720p или 1080p и разрешение видео 1080p
- ≥2 ГБ ОЗУ, пользовательский интерфейс 1080p и разрешение видео 1080p или 2160p
Это не означает, что приложения не должны заботиться об использовании памяти на этих устройствах, поскольку некоторые конкретные злоупотребления памятью все равно могут исчерпать доступную память и снизить производительность.
Цели памяти на ТВ-устройствах с малым объемом оперативной памяти
При измерении памяти на этих устройствах мы настоятельно рекомендуем контролировать каждый раздел памяти с помощью профилировщика памяти Android Studio . Телевизионные приложения должны отслеживать использование памяти и работать над тем, чтобы их категории были ниже пороговых значений, которые мы определяем в этом разделе.
В разделе «Как подсчитывается память» вы найдете подробное объяснение сообщаемых показателей памяти. Для определения порогов для ТВ-приложений мы сосредоточимся на трех категориях памяти:
- Анонимный + Обмен : состоит из памяти Java + Native + Stack в Android Studio.
- Графика : сообщается непосредственно в инструменте профилирования. Обычно состоит из графических текстур.
- Файл : сообщается как категории «Код» + «Другие» в Android Studio.
С учетом этих определений в следующей таблице указано максимальное значение, которое должен использовать каждый тип группы памяти:
Тип памяти | Цель | Цели использования (1 ГБ) |
---|---|---|
Анонимный + обмен (Java + собственный + стек) | Используется для выделения памяти, медиабуферов, переменных и других задач, требующих интенсивного использования памяти. | < 160 МБ |
Графика | Используется графическим процессором для текстур и буферов, связанных с отображением. | 30-40 МБ |
Файл | Используется для кодовых страниц и файлов в памяти. | 60-80 МБ |
Максимальный общий объем памяти (Anon+Swap + Graphics + File) не должен превышать следующее:
- 280 МБ общего использования памяти ( Anon+Swap + Graphics + File ) для устройств с низким объемом оперативной памяти 1 ГБ.
Настоятельно рекомендуется не превышать:
- Использование памяти 200 МБ ( Anon+Swap + Graphics ).
Память файлов
В качестве общего руководства по файловой памяти помните, что:
- В целом файловая память хорошо обрабатывается системой управления памятью ОС.
- На данный момент мы не обнаружили, что это является основной причиной нехватки памяти.
Однако при работе с файловой памятью в целом:
- Не включайте в сборку неиспользуемые библиотеки и по возможности используйте небольшие подмножества библиотек, а не полные.
- Не храните большие файлы открытыми в памяти и освобождайте их, как только закончите с ними.
- Минимизируйте размер скомпилированного кода для классов Java и Kotlin. См. руководство «Сжатие, запутывание и оптимизация приложения» .
Конкретные рекомендации по телевидению
В этом разделе представлены конкретные рекомендации по оптимизации использования памяти на ТВ-устройствах.
Графическая память
Используйте соответствующие форматы изображений и разрешения.
- Не загружайте изображения с разрешением, превышающим разрешение пользовательского интерфейса устройства. Например, изображения с разрешением 1080p следует уменьшить до 720p на устройстве с пользовательским интерфейсом 720p.
- По возможности используйте растровые изображения с аппаратной поддержкой .
- В таких библиотеках, как Glide, включите функцию
Downsampler.ALLOW_HARDWARE_CONFIG
, которая по умолчанию отключена. Включение этого параметра позволяет избежать дублирования растровых изображений, которые в противном случае находились бы как в графической, так и в анонимной памяти.
- В таких библиотеках, как Glide, включите функцию
- Избегайте промежуточных рендерингов и повторных рендерингов.
- Их можно определить с помощью Android GPU Inspector :
- Посмотрите в разделе «Текстуры» изображения, которые являются шагами к окончательному рендерингу, а не просто элементами, образующими их. Обычно это так называемый «промежуточный рендеринг».
- Для приложений Android SDK их часто можно удалить, используя флаг макета
forceHasOverlappedRendering:false
, чтобы отключить промежуточную визуализацию для этого макета. - См. «Избегайте перекрытия рендеров» о перекрывающихся рендерах как отличный ресурс.
- По возможности избегайте загрузки изображений-заполнителей , используйте
@android:color/
или@color
для текстур-заполнителей. - Избегайте объединения нескольких изображений на устройстве, если композицию можно выполнить в автономном режиме. Предпочитаю загружать отдельные изображения, а не компоновать изображения из загруженных изображений.
- Следуйте руководству «Обработка растровых изображений» , чтобы лучше работать с растровыми изображениями.
Анон+Подмена памяти
Anon+Swap состоит из выделений Native + Java + Stack в профилировщике памяти Android Studio. Используйте ActivityManager.isLowMemoryDevice()
чтобы проверить, ограничено ли устройство памятью, и адаптируйтесь к этой ситуации, следуя этим рекомендациям.
- СМИ:
- Укажите переменный размер медиа-буферов в зависимости от оперативной памяти устройства и разрешения воспроизведения видео . Это должно составлять 1 минуту воспроизведения видео:
- 40-60 МБ за 1 ГБ/1080p
- 60-80 МБ за 1,5 ГБ/1080p
- 80-100 МБ за 1,5 ГБ/2160p
- 100-120 МБ за 2 ГБ/2160p
- Свободное распределение памяти мультимедиа при изменении эпизода , чтобы предотвратить увеличение общего объема анонимной памяти.
- Освобождайте и останавливайте медиа-ресурсы сразу же после остановки приложения: используйте обратные вызовы жизненного цикла активности для обработки аудио- и видеоресурсов. Если вы не являетесь аудиоприложением, остановите воспроизведение , когда
onStop()
произойдет в ваших действиях, сохраните всю выполняемую вами работу и настройте освобождение ресурсов. Запланировать работу вам может понадобиться позже. См. раздел «Задания и сигналы тревоги» .- Вы можете использовать компоненты, учитывающие жизненный цикл, такие как
LiveData
иLifecycleOwner
чтобы помочь вам справиться с вызовами жизненного цикла Activity. - Чтобы обеспечить осведомленность о жизненном цикле вашей работы, вы также можете использовать сопрограммы и потоки Kotlin .
- Вы можете использовать компоненты, учитывающие жизненный цикл, такие как
- Обратите внимание на память буфера при поиске видео : разработчики часто выделяют дополнительные 15-60 секунд будущего контента, когда хотят подготовить видео для пользователя, но это создает дополнительные затраты памяти. В общем, не используйте будущий буфер более чем на 5 секунд, пока пользователь не выберет новую позицию видео. Если вам строго необходимо предварительно буферизовать дополнительное время во время поиска, обязательно выполните следующие действия:
- Заранее выделите буфер поиска и используйте его повторно.
- Размер буфера должен быть не более 15-25 МБ (в зависимости от памяти устройства).
- Укажите переменный размер медиа-буферов в зависимости от оперативной памяти устройства и разрешения воспроизведения видео . Это должно составлять 1 минуту воспроизведения видео:
- Распределения:
- Используйте рекомендации по графической памяти , чтобы не дублировать изображения в анонимной памяти.
- Изображения часто занимают большую часть памяти, поэтому их дублирование может оказать большую нагрузку на устройство. Это особенно актуально при интенсивной навигации по сетке изображений.
- Освободите выделения, удалив их ссылки при перемещении экранов . Убедитесь, что не осталось ссылок на растровые изображения и объекты.
- Используйте рекомендации по графической памяти , чтобы не дублировать изображения в анонимной памяти.
- Библиотеки:
- Профилируйте выделение памяти из библиотек при добавлении новых, поскольку они также могут загружать дополнительные библиотеки, которые также могут выделять память и создавать привязки .
- Сеть:
- Не выполняйте блокирующие сетевые вызовы во время запуска приложения , они замедляют время запуска приложения и создают дополнительные затраты памяти при запуске, где память особенно ограничена загрузкой приложения. Сначала покажите загрузочный экран или заставку и выполните сетевые запросы, как только пользовательский интерфейс будет готов.
Привязки
Привязки приводят к дополнительным затратам памяти, поскольку они помещают в память другие приложения или увеличивают потребление памяти привязанным приложением (если оно уже находится в памяти) для облегчения вызова API. В результате это уменьшает доступную память для приложения переднего плана. При привязке службы помните, когда и как долго вы используете привязку. Обязательно отпустите привязку, как только она станет ненужной.
Типичные привязки и лучшие практики:
- API целостности воспроизведения : используется для проверки целостности устройства.
- Проверьте целостность устройства после экрана загрузки и перед воспроизведением мультимедиа.
- Перед воспроизведением содержимого освободите ссылки на PlayIntegrity
StandardIntegrityManager
.
- Библиотека платежей Play : используется для управления подписками и покупками с помощью Google Play.
- Инициализируйте библиотеку после экрана загрузки и выполните всю работу по выставлению счетов перед воспроизведением любого мультимедиа.
- Используйте
BillingClient.endConnection()
после завершения использования библиотеки и всегда перед воспроизведением видео или мультимедиа. - Используйте
BillingClient.isReady()
иBillingClient.getConnectionState()
, чтобы проверить, была ли служба отключена, на случай, если какую-либо работу по выставлению счетов потребуется выполнить снова, а затем снова выполнитеBillingClient.endConnection()
после завершения.
- Поставщик шрифтов GMS
- Предпочитайте использовать автономные шрифты на устройствах с низким объемом оперативной памяти, а не использовать поставщика шрифтов, поскольку загрузка шрифтов обходится дорого, и FontsProvider будет связывать службы для этого.
- Библиотека Google Assistant : иногда используется для поиска и поиска в приложении, если возможно, замените эту библиотеку.
- Для приложений Leanback : используйте преобразование текста в речь Gboard или библиотеку androidx.leanback .
- Следуйте рекомендациям по поиску для реализации поиска.
- Примечание. Функция Leanback устарела , и приложения следует перенести в функцию TV Compose.
- Для приложений «Создать» :
- Используйте преобразование текста в речь Gboard для реализации голосового поиска.
- Внедрите Watch Next, чтобы сделать медиаконтент в вашем приложении доступным для обнаружения.
- Для приложений Leanback : используйте преобразование текста в речь Gboard или библиотеку androidx.leanback .
Службы переднего плана
Службы переднего плана — это особый тип службы, привязанный к уведомлению. Это уведомление отображается в области уведомлений на телефонах и планшетах, но на телевизионных устройствах нет панели уведомлений в том же смысле, что и на этих устройствах. Даже если службы переднего плана полезны, поскольку их можно продолжать работать, пока приложение находится в фоновом режиме, телевизионные приложения должны следовать следующим рекомендациям:
В Android TV и Google TV службам Foreground Services разрешено продолжать работу только после того, как пользователь покинет приложение:
- Для аудиоприложений : службам переднего плана разрешено продолжать работу только после того, как пользователь покинет приложение, чтобы продолжить воспроизведение звуковой дорожки. Службу необходимо остановить сразу после окончания воспроизведения звука.
- Для любого другого приложения: все службы переднего плана должны быть остановлены, как только пользователь покинет ваше приложение , поскольку нет уведомления, уведомляющего пользователя о том, что приложение все еще работает и потребляет ресурсы.
- Для фоновых заданий, таких как обновление рекомендаций или «Смотреть дальше» , используйте
WorkManager
.
Работы и сигналы тревоги
WorkManager
— это современный API-интерфейс Android для планирования повторяющихся фоновых заданий. WorkManager будет использовать новый JobScheduler
, если он доступен (SDK 23+), и старый AlarmManager
если он отсутствует. Для получения передового опыта выполнения запланированных заданий на телевидении следуйте следующим рекомендациям:
- Избегайте использования API-интерфейсов
AlarmManager
в SDK 23+, особенноAlarmManager.set()
,AlarmManager.setExact()
и подобных методов, поскольку они не позволяют системе определять подходящее время для запуска заданий (например, когда устройство работает на холостом ходу). - На устройствах с низким объемом оперативной памяти избегайте запуска заданий без крайней необходимости. При необходимости используйте WorkManager
WorkRequest
только для обновления рекомендаций после воспроизведения и попытайтесь сделать это, пока приложение еще открыто. - Определите
Constraints
WorkManager, чтобы система могла запускать ваши задания в подходящее время:
Котлин
Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .setRequiresStorageNotLow(true) .setRequiresDeviceIdle(true) .build()
Ява
Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .setRequiresStorageNotLow(true) .setRequiresDeviceIdle(true) .build()
- Если вам необходимо регулярно запускать задания (например, чтобы обновлять Watch Next на основе активности пользователя по просмотру контента в вашем приложении на другом устройстве), снижайте использование памяти, чтобы потребление памяти заданием не превышало 30 МБ .
Другие общие рекомендации
Следующие рекомендации предоставляют общую информацию о разработке приложений для Android:
- Минимизируйте выделение объектов, оптимизируйте повторное использование объектов и оперативно освобождайте неиспользуемые объекты.
- Не храните ссылки на объекты, особенно растровые изображения.
- Избегайте использования
System.gc()
и вызовов прямого освобождения памяти, поскольку они мешают процессу обработки памяти в системе. Например, в устройствах, использующих zRAM, принудительный вызовgc()
может временно увеличить использование памяти из-за сжатия и распаковки памяти. память. - Используйте
LazyList
например, как показано в браузере каталога в Compose илиRecyclerView
в уже устаревшем наборе инструментов пользовательского интерфейса Leanback, чтобы повторно использовать представления, а не заново создавать элементы списка. - Кэшируйте локально элементы, считываемые от внешних поставщиков контента, которые вряд ли изменятся, и определяют интервалы обновления, которые предотвращают выделение дополнительной внешней памяти.
- Проверьте возможные утечки памяти.
- Остерегайтесь типичных случаев утечки памяти , таких как ссылки внутри анонимных потоков, перераспределение видеобуферов, которые никогда не освобождаются, и другие подобные ситуации.
- Используйте дамп кучи для устранения утечек памяти.
- Создавайте базовые профили , чтобы минимизировать объем своевременной компиляции, необходимой при запуске приложения при холодном запуске.
Обзор инструментов
- Используйте инструмент профилирования памяти Android Studio , чтобы проверить потребление памяти во время использования.
- Используйте heapdump для проверки распределения определенных объектов и растровых изображений.
- Используйте собственный профилировщик памяти для проверки распределений, отличных от Java или Kotlin.
- Используйте Android GPU Inspector для проверки распределения графики.