Анализ и оптимизация запуска приложений

Во время запуска приложения ваше приложение производит первое впечатление на пользователей. Запуск приложения должен быть быстрым, чтобы загружать и отображать информацию, необходимую пользователю для использования вашего приложения. Если ваше приложение запускается слишком долго, пользователи могут выйти из него, потому что они ждут слишком долго.

Мы рекомендуем использовать библиотеку Macrobenchmark для измерения запуска . Библиотека предоставляет обзор и подробные трассировки системы, чтобы точно увидеть, что происходит во время запуска.

Системные трассировки предоставляют полезную информацию о том, что происходит на вашем устройстве, что помогает понять, что делает ваше приложение во время запуска, и определить потенциальные области для оптимизации.

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

Шаги по анализу и оптимизации запуска

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

Чтобы найти компромисс в производительности, учтите следующее:

  • Используйте библиотеку Macrobenchmark для измерения времени, затрачиваемого на каждую операцию, и определения блоков, выполнение которых занимает много времени.

  • Убедитесь, что ресурсоемкая операция важна для запуска приложения. Если операция может дождаться полной прорисовки приложения, это поможет минимизировать ограничения ресурсов при запуске.

  • Убедитесь, что вы ожидаете, что эта операция будет выполняться при запуске приложения. Часто ненужные операции могут быть вызваны из устаревшего кода или сторонних библиотек.

  • Если возможно, переместите длительные операции в фоновый режим. Фоновые процессы по-прежнему могут влиять на использование ЦП во время запуска.

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

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

Измеряйте и анализируйте время, затраченное на основные операции

Когда у вас есть полная трассировка запуска приложения, просмотрите ее и измерьте время, затраченное на основные операции, такие как bindApplication или activityStart . Мы рекомендуем использовать Perfetto или профилировщики Android Studio для анализа этих следов.

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

  • Занимают большие временные рамки и могут быть оптимизированы. Каждая миллисекунда имеет значение для производительности. Например, обратите внимание на время отрисовки Choreographer , время развертывания макета, время загрузки библиотеки, транзакции Binder или время загрузки ресурсов. Для начала посмотрите на все операции, которые занимают больше 20 мс.
  • Заблокируйте основной поток. Дополнительные сведения см. в разделе Навигация по отчету Systrace .
  • Не нужно запускать во время запуска.
  • Можно подождать, пока не будет нарисован первый кадр.

Изучите каждую из этих трассировок, чтобы найти пробелы в производительности.

Определить дорогостоящие операции в основном потоке

Лучше всего не выполнять дорогостоящие операции, такие как файловый ввод-вывод и доступ к сети, из основного потока. Это не менее важно во время запуска приложения, поскольку дорогостоящие операции в основном потоке могут привести к тому, что приложение перестанет отвечать на запросы и задержит выполнение других важных операций. StrictMode.ThreadPolicy может помочь выявить случаи, когда в основном потоке выполняются дорогостоящие операции. Рекомендуется включать StrictMode в отладочных сборках, чтобы выявлять проблемы как можно раньше, как показано в следующем примере:

Котлин

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        ...
        if (BuildConfig.DEBUG)
            StrictMode.setThreadPolicy(
                StrictMode.ThreadPolicy.Builder()
                    .detectAll()
                    .penaltyDeath()
                    .build()
            )
        ...
    }
}

Ява

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        ...
        if(BuildConfig.DEBUG) {
            StrictMode.setThreadPolicy(
                    new StrictMode.ThreadPolicy.Builder()
                            .detectAll()
                            .penaltyDeath()
                            .build()
            );
        }
        ...
    }
}

Использование StrictMode.ThreadPolicy включает политику потоков во всех отладочных сборках и приводит к сбою приложения при обнаружении нарушений политики потоков, что затрудняет пропущение нарушений политики потоков.

ТТИД и ТТФД

Чтобы узнать, сколько времени требуется приложению для создания первого кадра, измерьте время до начального отображения (TTID). Однако эта метрика не обязательно отражает время, пока пользователь не сможет начать взаимодействовать с вашим приложением. Метрика времени до полного отображения (TTFD) более полезна при измерении и оптимизации путей кода, необходимых для обеспечения полностью пригодного к использованию состояния приложения.

Стратегии создания отчетов о том, что пользовательский интерфейс приложения полностью прорисован, см. в разделе «Повышение точности времени запуска» .

Оптимизируйте как TTID, так и TTFD, поскольку оба важны в своих областях. Короткий TTID помогает пользователю увидеть, что приложение действительно запускается. Важно сделать TTFD коротким, чтобы пользователь мог быстро начать взаимодействовать с приложением.

Анализ общего состояния потока

Выберите время запуска приложения и просмотрите общие фрагменты потока. Основной поток должен всегда реагировать.

Такие инструменты, как Android Studio Profiler и Perfetto, предоставляют подробный обзор основного потока и количества времени, потраченного на каждом этапе. Дополнительные сведения о визуализации трассировок perfetto см. в документации по пользовательскому интерфейсу Perfetto .

Определите основные фрагменты состояния сна основного потока.

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

Уменьшите блокировку основного потока и бесперебойный сон.

Ищите каждый экземпляр основного потока, переходящего в заблокированное состояние. Perfetto и Studio Profiler показывают это оранжевым индикатором на временной шкале состояний потока. Определите операции, выясните, ожидаемы ли они или их можно избежать, и при необходимости оптимизируйте.

Прерываемый сон, связанный с IO, может стать действительно хорошей возможностью для улучшения. Другие процессы, выполняющие ввод-вывод, даже если это несвязанные приложения, могут конкурировать с вводом-выводом, который выполняет приложение верхнего уровня.

Улучшить время запуска

После того, как вы определите возможность оптимизации, изучите возможные решения, которые помогут сократить время запуска:

  • Загружайте контент лениво и асинхронно, чтобы ускорить TTID .
  • Минимизируйте вызовы функций, которые выполняют вызовы связующих. Если они неизбежны, убедитесь, что вы оптимизируете эти вызовы путем кэширования значений вместо повторения вызовов или перемещения неблокирующей работы в фоновые потоки.
  • Чтобы запуск вашего приложения происходил быстрее, вы можете как можно быстрее отображать пользователю что-то, что требует минимального рендеринга, пока остальная часть экрана не загрузится.
  • Создайте и добавьте профиль запуска в свое приложение.
  • Используйте библиотеку запуска приложений Jetpack, чтобы упростить инициализацию компонентов во время запуска приложения.

Анализируйте производительность пользовательского интерфейса

Запуск приложения включает в себя заставку и время загрузки вашей домашней страницы. Чтобы оптимизировать запуск приложения, проверьте трассировки, чтобы понять, сколько времени требуется на отрисовку пользовательского интерфейса.

Ограничить работу по инициализации

Загрузка некоторых кадров может занять больше времени, чем другие. Это считается дорогостоящей тратой для приложения.

Чтобы оптимизировать инициализацию, выполните следующие действия:

  • Отдавайте предпочтение медленным проходам макета и выбирайте их для улучшений.
  • Исследуйте каждое предупреждение от Perfetto и оповещение от Systrace, добавляя собственные события трассировки, чтобы сократить дорогостоящие отрисовки и задержки.

Измерение данных кадра

Существует несколько способов измерения данных кадра. Пять основных методов сбора:

  • Локальный сбор с использованием dumpsys gfxinfo : не все кадры, наблюдаемые в данных dumpsys, ответственны за медленный рендеринг вашего приложения или оказывают какое-либо влияние на конечных пользователей. Тем не менее, это хороший показатель для анализа различных циклов выпуска, чтобы понять общую тенденцию производительности. Чтобы узнать больше об использовании gfxinfo и framestats для интеграции измерений производительности пользовательского интерфейса в ваши методы тестирования, см. Основы тестирования приложений Android .
  • Сбор полей с помощью JankStats . Собирайте время рендеринга кадров из определенных частей вашего приложения с помощью библиотеки JankStats , записывайте и анализируйте данные.
  • В тестах с использованием Macrobenchmark (Perfetto под капотом)
  • Perfetto FrameTimeline : на Android 12 (уровень API 31) вы можете собирать метрики временной шкалы кадров из трассировки Perfetto, работа которой вызывает выпадение кадров. Это может быть первым шагом к диагностике того, почему пропадают кадры.
  • Android Studio Profiler для обнаружения мусора

Проверьте время загрузки основного действия

Основная деятельность вашего приложения может содержать большой объем информации, загружаемой из нескольких источников. Проверьте макет домашней Activity и особенно обратите внимание на метод Choreographer.onDraw домашней активности.

  • Используйте reportFullyDrawn , чтобы сообщить системе, что ваше приложение теперь полностью прорисовано в целях оптимизации.
  • Измеряйте активность и запуски приложений с помощью StartupTimingMetric с библиотекой Macrobenchmark.
  • Посмотрите на пропадание кадров.
  • Определите макеты, требующие много времени для визуализации или измерения.
  • Определите ресурсы, которые загружаются долго.
  • Определите ненужные макеты, которые раздуваются при запуске.

Рассмотрите следующие возможные решения для оптимизации времени загрузки основного действия:

  • Сделайте первоначальный макет максимально простым. Дополнительные сведения см. в разделе Оптимизация иерархий макетов .
  • Добавьте пользовательские точки трассировки, чтобы предоставить дополнительную информацию о пропущенных кадрах и сложных макетах.
  • Минимизируйте количество и размер ресурсов растровых изображений, загружаемых во время запуска.
  • Используйте ViewStub , если макеты не VISIBLE сразу. ViewStub — это невидимое представление нулевого размера, которое можно использовать для ленивого увеличения ресурсов макета во время выполнения. Для получения дополнительной информации см. ViewStub .

    Если вы используете Jetpack Compose , вы можете получить поведение, аналогичное ViewStub , используя состояние для отсрочки загрузки некоторых компонентов:

    var shouldLoad by remember {mutableStateOf(false)}
    
    if (shouldLoad) {
     MyComposable()
    }
    

    Загрузите составные элементы внутри условного блока, изменив shouldLoad :

    LaunchedEffect(Unit) {
     shouldLoad = true
    }
    

    Это запускает рекомпозицию, включающую код внутри условного блока в первом фрагменте.

{% дословно %} {% дословно %} {% дословно%} {% дословно %}