Разработка
Улучшение времени запуска приложений на Android: уроки Facebook
Работая вместе, команда Google Android и команда Facebook согласовали определение метрик запуска приложений и лучшие практики, и поделились ими в этой статье.
Улучшение времени запуска приложения — нетривиальная задача и требует глубокого понимания вещей, которые на нее влияют. В этом году команда Google Android и команда приложения Facebook совместно работали над метриками и обменивались подходами для улучшения запуска приложений. В общедоступной документации Google Android содержится много информации об оптимизации запуска приложений. В дополнение к этому мы хотим поделиться тем, как это применялось к приложению Facebook и что помогло им улучшить запуск приложения.
Сейчас Facebook ежемесячно используют более 2.9 миллиарда человек. Facebook помогает людям создавать сообщества и сближает мир. Это место, где люди могут делиться жизненными моментами, узнавать и обсуждать происходящее, налаживать и развивать отношения, а также вместе работать над созданием экономических возможностей.
Разработчики приложений Facebook стремятся к тому, чтобы у людей был лучший опыт и чтобы приложение безупречно работало на всех устройствах в любой стране и в различных сетевых условиях. Работая вместе, команда Google Android и команда Facebook согласовали определение метрик запуска приложений и лучшие практики, и поделились ими в этой статье.
С чего начать
Начните с измерения времени запуска. Это позволит вам узнать, насколько хорош ваш пользовательский опыт при запуске, отслеживать любые изменения, а также понять, сколько стоит вложить в улучшения. В конце концов, время запуска должно быть привязано к удовлетворенности пользователей, их вовлеченности или росту пользовательской базы, чтобы расставить приоритеты для ваших инвестиций.
Android определяет две метрики для измерения времени запуска приложения: время до полного отображения (Time-To-Full-Display, TTFD) и время до начала отображения (Time-To-Initial-Display, TTID). Хотя вы можете дополнительно разделить его на время холодного/теплого старта, этот пост не делает однозначного различия между ними — подход Facebook состоит в том, чтобы измерить и оптимизировать время запуска, которое переживают все пользователи, взаимодействующие с приложением (некоторые из запусков будут холодными, некоторые теплыми).
Время до полного отображения, Time-To-Full-Display
TTFD фиксирует время, когда ваше приложение завершило рендеринг и готово к взаимодействию с пользователем и работе, возможно, включая загрузку контента из хранилища или сети. Это может занять некоторое время в медленных сетях и может зависеть от того, на какой экран попадают ваши пользователи. Таким образом, может быть полезно показать что-то сразу и позволить пользователям увидеть, что прогресс идет, что подводит нас к TTID…
Время до начального отображения, Time-To-Initial-Display
TTID фиксирует время, в течение которого ваше приложение отрисовывает фон, навигацию, любой быстро загружаемый локальный контент, заполнители для более медленного локального контента или контента, поступающего из сети. TTID показывает, когда пользователи могут перемещаться и добираться туда, куда они хотят.
Сосредоточьтесь на успехе пользователей
Пользователи обращаются к вашему приложению за контентом, загрузка которого может занять некоторое время, и вы хотите доставить им этот контент как можно быстрее.
Разработчики приложений Facebook сосредотачиваются на метрике, основанной на времени до полного отображения (TTFD), в которой есть весь контент и изображения, потому что это и есть полный опыт того, ради чего пользователи пришли в приложение. Если сетевой запрос контента или изображений занимает много времени или терпит неудачу, разработчики хотят знать об этом, чтобы они могли улучшить в процессе запуска.
Какова хорошая цель для TTID и TTFD?
Метрика запуска Facebook — это процент запусков приложения, которые они считают «плохими», то есть любой запуск, для которого TTFD превышает 2.5 секунды, ИЛИ любая часть запуска, которая не удалась (например, не удается загрузить изображение или приложение дает сбой). Facebook фокусируется на снижении этого процента неудачных запусков либо путем улучшения успешных запусков, которые занимают более 2.5 секунд, либо путем устранения проблем, вызывающих неудачные запуски. Метрика в 2.5 секунды была выбрана на основе исследования, которое показало, что это имеет значение для пользователей Facebook (это также соответствует метрике Largest Contentful Paint (LCP) в рекомендациях Web Vitals для веб-сайтов).
Включение полного опыта в TTFD, особенно любых сетевых вызовов для получения недавнего контента, может сделать ваш показатель запуска очень медленными по сравнению с TTID. На самом деле это хорошо! Он представляет реальный опыт пользователей вашего приложения. Усовершенствования, которые вы вносите в это приложение, могут способствовать более активному использованию и восприятию пользователями производительности вашего приложения, как это было в Facebook.
Измерение TTFD может быть сложной задачей в зависимости от вашего приложения. Если это слишком сложно, можно начать с Time To Initial Display. Это может привести к потере данных о производительности загрузки части вашего контента, если у вас есть заполнители или изображения, но хорошо начать с чего-то, даже если это всего лишь часть того, что ваши пользователи видят при взаимодействии с вашим приложением каждый день.
Инструментарий TTID
В Android 4.4 (уровень API 19) и выше logcat предоставляет значение Displayed, фиксирующее время, прошедшее между запуском процесса и завершением отрисовки первого кадра соответствующей Activity на экране.
Строка лога выглядит примерно так:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms
Инструментарий TTFD
Чтобы использовать TTFD, вызовите reportFullyDrawn() в Activity после того, как весь ваш контент появится на экране. Не забудьте включить любой контент, который заменяет заполнители, а также любые изображения, которые вы визуализируете (обязательно учитывайте, когда отображается само изображение, а не только его плейсхолдер). Как только вы используете reportFullyDrawn(), вы можете увидеть это в logcat:
ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms
Рекомендации разработчиков Facebook
Разработчики приложений Facebook уже много лет оптимизируют приложение для миллиардов пользователей на множестве устройств, платформ и стран. В этом разделе рассказывается о некоторых ключевых уроках, которые разработчики приложений Facebook применили для оптимизации запуска своих приложений.
- Сначала поймите, потом оптимизируйте. После того, как вы определили хорошую метрику для запуска, ее использование в приложении позволит вам понять и расставить приоритеты в улучшении эффективности запуска, чтобы обеспечить лучший опыт для пользователей. Начав с измерения, вы сможете понять, что есть возможность, вы можете определить, на чем сосредоточить свои усилия, и вы увидите, насколько вы улучшили ситуацию, когда начнете оптимизацию.
- Сначала исправляйте сбои. После того, как вы измерили запуск, убедитесь, что ваше приложение запускается надежно. Сбои во время запуска — самый неприятный и самый быстрый способ заставить пользователей покинуть ваше приложение. Измерьте и устраните их в первую очередь.
- Не забывайте о функциональной надежности — ваше приложение показывает какой-то контент быстро, но не загружает весь контент или он загружается много времени? Ваше приложение может запускаться быстро, но не работать так, как хочет клиент (например, если нажатие кнопки не работает), это ухудшает пользовательский опыт.
- Стремитесь к согласованности — непостоянная производительность больше разочаровывает, чем медленная, но постоянная. Взгляните на “длинный хвост” своих запусков и посмотрите, есть ли какие-либо исправления или способы смягчить эти медленные запуски. Не забывайте следить за запусками без сети в офлайн-режиме и за запусками в сетях с потерями.
- Распараллеливание работы — большинство современных телефонов имеют как минимум 4 ядра, поэтому есть место для многозадачности! Не блокируйте основной поток без необходимости. Выведите I/O и некритические работы за пределы основного потока.
- Будь «ленивы» — как только у вас будет надежный и стабильный запуск, просмотрите все, что вы делаете, чтобы отобразить свой первый видимый экран с контентом — есть ли там какая-то работа, в которой нет необходимости? Удалите, отложите или переместите в фоновый режим любую работу, которая не связана напрямую с запуском приложения, до тех пор, пока приложение не будет запущено (но будьте осторожны и следите за отзывчивостью вашего приложения в качестве контрметрики). Постарайтесь сделать onCreate() вашего приложения максимально легким. Вы также можете воспользоваться библиотекой Jetpack App Startup для инициализации компонентов при запуске приложения. При этом убедитесь, что загружены все необходимые модули для старта Activity и нет изменений там, где становятся доступными lazily-loaded модули.
- Демонстрируйте прогресс, но не меняйте интерфейс слишком сильно. Старайтесь не слишком сильно менять то, что предлагается пользователям во время запуска. Прискорбно пытаться нажимать на что-то только для того, чтобы это потом изменилось. Это похоже на концепцию Cumulative Layout Shift (CLS) из Web Vitals. Для сетевых загрузок с неопределенной продолжительностью закройте сплеш-скрин и покажите заполнители для асинхронной загрузки. Рассмотрите возможность применения анимации к области содержимого, отражающей состояние загрузки. Убедитесь, что структура загруженного содержимого максимально соответствует скелетной структуре, чтобы обеспечить плавный переход к ней после загрузки содержимого.
- Кэшируйте — когда пользователь впервые открывает ваше приложение, вы можете отобразить индикаторы загрузки для некоторых элементов пользовательского интерфейса. В следующий раз, когда пользователь зайдет в ваше приложение, вы можете показать кэшированное содержимое при загрузке более свежего контента. Вы когда-нибудь видели обновление вашего фида FB после загрузки вашего приложения, когда мы получаем обновленный контент из сети? Сокращение времени сетевых запросов в вашем старте — отличный способ ускорить процесс и обеспечить более стабильную производительность при запуске. Однако показ кэшированного содержимого не всегда может быть лучшим подходом, как описано в следующем пункте, и поэтому важно определить, что лучше работает для клиента.
- Работайте быстро и медленно — немного более медленный, свежий и релевантный контент может быть лучше, чем быстро устаревший контент. Показ свежего контента вашим пользователям может быть более ценным, чем сверхбыстрый запуск только для обновления контента вскоре после запуска. Оцените, лучше ли оптимизировать показ свежего контента как можно быстрее с тайм-аутом для показа устаревшего контента, если сеть медленная, или просто сразу показать то, что доступно, если сеть отключена.
- Последовательность для начала сеанса — может оказаться полезным сбросить пользователей до основного контента после того, как ваше приложение долгое время находится в фоновом режиме. Устройства могут сохранять ваше приложение в памяти в течение длительного времени.
- Посмотрите на внутреннюю работу. Отследите и посмотрите, что выполняется во время запуска, или подключите отладчик — вы можете быть удивлены тем, что обнаружите! Как только вы получите хорошее представление о старте, вы сможете эффективно оптимизировать производительность своего приложения. Так вы сможете инвестировать свои усилия в свои самые большие возможности, потому что вы будете знать, где они.
- Упростите выполнение правильных действий. Иногда разработчики используют плохие шаблоны и архитектуру, потому что существует слишком много способов сделать что-то. Не бойтесь объединить шаблоны, используемые в вашем приложении, и оптимизировать их, чтобы было легко выбрать, как выполнить задачу, и чтобы эта задача была эффективной. Хорошим примером этого могут быть шаблоны “нетерпеливого” выполнения кода. Если вы на старте запускаете код для контента, который появляется только после первой полноэкранной отрисовки, вы по определению снижаете производительность. Ленивое выполнение кода — хороший шаблон. Активно запускайте код только тогда, когда он критически блокирует ваш запуск.
Рекомендации от команды Google Android
Рекомендации команды Google Android по измерению и оптимизации запуска приложений доступны в общедоступных документах: App startup time. В этом разделе обобщены некоторые ключевые моменты, которые связаны с приведенными выше рекомендациями Facebook, которые следует учитывать всем разработчикам приложений для Android.
- TTID и TTFD — важные метрики для запуска приложения. Google Android показывает TTID в Play Console. TTFD — это расширенная метрика TTID, поэтому любые улучшения TTID должны применяться к обоим показателям.
- Вызовите reportFullyDrawn(), чтобы получить TTFD и сообщить системе, что рендеринг вашей Activity завершен. Чтобы улучшить запуск приложения, система Android настраивает оптимизацию, чтобы расставить приоритеты для задач, которая выполняются до вызова reportFullyDrawn(). Вызов этого метода, когда ваше приложение находится в полностью пригодном для использования состоянии, сократит время запуска вашего приложения. Каждое приложение должно использовать этот API! И не забудьте измерять этот показатель.
- Мониторинг технических характеристик вашего приложения с помощью Android Vitals поможет вам улучшить запуск вашего приложения. Используя Play Console, вы можете просматривать данные, которые помогут вам понять и сократить время запуска вашего приложения и многое другое.
- Мы знаем, что исправление ошибки в рабочей среде намного дороже, чем исправление во время разработки. То же самое и с производительностью. Настройте свое приложение для измерения запуска приложений на раннем этапе с помощью локальных тестов производительности с помощью Jetpack Macrobenchmark: Startup.
- Как мы уже говорили выше, измерения — это ключ к пониманию и оптимизации старта. Android предлагает system tracing, который может помочь глубже изучить и диагностировать проблемы с запуском приложений.
- Библиотека Jetpack App startup обеспечивает простой и эффективный способ инициализации компонентов при запуске приложения. И разработчики библиотек, и разработчики приложений могут использовать эту библиотеку для оптимизации последовательностей запуска и явного задания порядка инициализации. Вы можете использовать эту библиотеку, чтобы указать, какие компоненты в какие моменты запуска загружаются.
- Типичная проблема, которая влияет на запуск приложения, — это слишком много действий во время инициализации. Например, создание больших или сложных макетов, блокировка отрисовки экрана, загрузка и декодирование растровых изображений, сборка мусора и т.д.
Резюме
В этой статье описаны некоторые ключевые показатели запуска и передовые практики по улучшению опыта, которые помогают улучшить вовлеченность пользователей приложения Facebook для Android. В ней также представляются метрики, библиотеки и инструменты, рекомендованные командой Google Android. Любое приложение для Android выиграет от применения некоторых из стратегий, описанных в статье. Измерьте и сделайте запуск вашего приложения приятным и быстрым для ваших пользователей!