Достигаем бизнес-целей с сильным digital-продуктом
Заполните форму, мы свяжемся с вами и обсудим задачу
Мы⦁используем cookie-файлы, необходимые для⦁работы нашего сайта. Продолжая использовать сайт, Вы⦁соглашаетесь со⦁сбором и⦁обработкой данных. Подробнее

Хватит думать о себе! Оптимизация андроид приложения

«В последнее время меня все чаще посещает мысль, что все думают о разработчиках, но забывают о пользователях» — сказал недавно наш Android-разработчик Марат Джеманкулов.

«Мы видим кучу статей об архитектуре, новых технологиях. Какова же картина на реальных приложениях? Огромное количество пользователей ругаются на низкую производительность, большое потребление памяти, а также бесконечное количество сервисов, висящих в фоне и тратящих батарею.»

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

Утечки памяти

Думаю, ни для кого не секрет, что в рамках этой статьи данная тема обязательна к освещению. Утечки памяти. Все говорят, что их нужно избегать, но мало кто говорит что можно сделать и как обнаружить.

Начнем с того, что же называется «утечкой памяти». В строгом понимании, объект можно назвать утечкой памяти, если он продолжает существовать в памяти даже после того, как на него потеряны все ссылки. Подобное может не только замедлить наше устройство, но и привести к неожиданному поведению, вызвать баги. К примеру, вы отправляете запрос каждые 20 секунд в Runnable на новом потоке. Не будем сейчас думать о том, что у нас есть lifecycle- и viewModelScope, которые автоматически очищаются вместе с их родителями. Представим старое приложение, работающее на потоках. Передадим наш Runnable в поток и запустим. Что мы видим? Картина такова, что вполне возможно, что даже при выходе с активити, вы будете продолжать отправлять запросы, так как ссылка все еще живая. Думаю, что такое поведение вряд ли кого-то устроит. Так что же делать?

Используйте встроенный профайлер в андроид студии на выявление GC Leaks. Самый простой из способов выявления утечек и неэкономного использования памяти. Профайлер встроен в андроид студию, находится на видном месте и весьма легок в использовании.

Использование инструмента, созданного компанией Square (да-да, той самой, что создали Retrofit). Называется этот инструмент LeakCanary. Что он делает? Эта канарейка ищет по приложению неиспользуемые ссылки и, в случае если они есть, выдает уведомление. Что приятно, клик на уведомление переводит нас на новую активити, в которой вы можете увидеть, как произошла утечка и с каким именно объектом, для последующего устранения. Чтобы использовать библиотеку, нужно всего лишь импортировать ее с помощью debugImplementation. Просто в использовании, но представляет собой удобный и важный инструмент, почему бы и нет?

Вещь, о которой мало кто говорит, но ее необходимо знать. Аккуратно используйте методы по типу lifecycleScope.launchWhenStarted. Использование данного метода внутри onStart вызовет утечку памяти. Вызов launchWhenStarted должен быть не позднее чем в onCreate.

Используйте ленивую инициализацию

Это оптимизирует использование объектов при работе с классом, в котором вы работаете. При помощи ленивой инициализации вы дадите пользователю больше места для работы, так как не будете растрачивать драгоценную память понапрасну. Но будьте аккуратны, не передавайте в byLazy экземпляры фрагментов, активити и тому подобное.

Так, к примеру, при передаче в byLazy экземпляр Activity, вы получите утечку памяти, если ваша переменная не вызовется в процессе работы программы. Это произойдет, так как byLazy будет хранить ссылку на объект и не очистит ее самостоятельно.

Удаление ненужных фич при нехватке памяти

Используйте onTrimMemory (level: Int). Зачем нужен данный метод? Все понятно по его названию. Здесь вы можете отследить то, как ведет себя память на устройстве. При недостатке памяти вы можете использовать 2 варианта:

  • Первым делом отключите фоновые сервисы, которые используют много памяти. Отключите запросы на геолокацию или уменьшите количество запросов в сеть. Пользователь будет больше благодарен тому, что у него не лагает картинка на устройстве, чем геолокации, обновляющейся каждые полсекунды.
  • Если и прошлый вариант не работает — добавьте в манифест флаг android: largeHeap="true" для увеличения размера heap вашего приложения. (Для тех кто в танке, куча или heap — Эта часть памяти хранит в памяти фактические объекты, на которые ссылаются переменные из стека). Таким образом вы увеличите количество памяти, которые может использовать ваше приложение. Используйте этот инструмент крайне аккуратно. В большинстве приложений такое использовать крайне не рекомендуется, но это просто необходимо при написании, например, графического редактора.

Используйте оптимизации иерархии view

При создании дизайна всегда думайте о том, как оптимально расположить лейауты. К примеру, не используйте наложение нескольких LinearLayout’ов.Это вызовет чрезмерное наслаивание view. Также не используйте создание background для объектов, в которых это не необходимо. Подобные операции вызовут так называемый overdraw (перерисовку). Overdraw легко вызовет проблемы с производительностью. Почему? Наша любимая система очень тщательно прорисовывает каждый объект, в том числе и фон каждого объекта. Для просмотра приложения на перерисовку используйте пункт «Показывать превышение GPU» в настройках разработчика.

А что там по Compose?

Нам всем прекрасно известно, как использование Jetpack Compose меняет привычные вещи. Все говорят, что использование данной технологии упрощает написание приложений для Android, но я твердо уверен: чем проще писать код, тем проще его испортить. Любая сильно развитая технология может заметно замедлить ваше приложение. При использовании Jetpack Compose также существуют некоторые рекомендации для улучшения производительности.

Используйте рекомпозицию верно

Думайте о том, как будет происходить рекомпозиция в вашем приложении. Избегайте ее чрезвычайного использования. Используйте @Stable или @Immutable для стейтов, которые считаете однозначно неизменяемыми.

Оптимизируйте списки

Используйте параметр key для LazyColumn или LazyRow. Частично данный совет подходит под определение прошлого, но я считаю, что его необходимо вынести в отдельную категорию из-за его важности и широкого применения.

@Composable
fun TestColumn () {
    LazyColumn (someList, { item -> item. id}){
        Text (it.toString ())
    }
}

Данный совет поможет переиспользованию уже существующих элементов.

Выводы

Вывод из всего вышесказанного всего один — пишите осознанно, рассматривая каждый случай как новый. Думайте о том, как переиспользуются и перерисовываются компоненты, делая все лучше и лучше каждое новое приложение. Есть идеи по оптимизации? Пиши в комментариях!