Измеряйте время загрузки и рендеринг экрана с помощью Firebase Performance Monitoring.

1. Введение

Последнее обновление: 11 марта 2021 г.

Зачем нам нужно измерять производительность представлений?

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

Разве Firebase Performance Monitoring не предоставляет эти показатели производительности «из коробки»?

Firebase Performance Monitoring автоматически фиксирует некоторые данные о производительности, такие как время запуска вашего приложения (т. е. время загрузки только для вашего первого действия) и производительность рендеринга экрана (т. Фрагменты). Однако в отраслевых приложениях обычно не так много действий, а есть одно действие и несколько фрагментов. Кроме того, многие приложения обычно реализуют свои собственные настраиваемые представления для более сложных вариантов использования. Поэтому часто бывает полезно понять, как измерять время загрузки и производительность рендеринга экрана как для действий, так и для фрагментов, используя пользовательские трассировки кода в своем приложении. Вы можете легко расширить эту кодовую лабораторию для измерения производительности компонентов Custom View.

Что вы узнаете

  • Как добавить мониторинг производительности Firebase в приложение для Android
  • Понимание загрузки Activity или Fragment
  • Как использовать пользовательские трассировки кода для измерения времени загрузки действия или фрагмента
  • Понимание рендеринга экрана и что такое Slow/Frozen frame
  • Как оснастить пользовательские трассировки кода метриками для записи экранов Slow/Frozen
  • Как просмотреть собранные метрики в консоли Firebase

Что вам понадобится

  • Android Studio 4.0 или выше
  • Android-устройство/эмулятор
  • Java версии 8 или выше

2. Настройка

Получить код

Выполните следующие команды, чтобы клонировать пример кода для этой лаборатории кода. Это создаст на вашем компьютере папку с именем codelab-measure-android-view-performance :

$ git clone https://github.com/FirebaseExtended/codelab-measure-android-view-performance.git
$ cd codelab-measure-android-view-performance

Если на вашем компьютере нет git, вы также можете скачать код напрямую с GitHub.

Импортируйте проект measure-view-performance-start в Android Studio. Вы, вероятно, увидите некоторые ошибки компиляции или, возможно, предупреждение об отсутствии файла google-services.json . Мы исправим это в следующем разделе этого шага.

В этой лаборатории кода мы будем использовать плагин Firebase Assistant для регистрации нашего приложения Android в проекте Firebase и добавления необходимых файлов конфигурации, плагинов и зависимостей Firebase в наш проект Android — и все это из Android Studio !

Подключите свое приложение к Firebase

  1. Перейдите в Android Studio / Справка > Проверить наличие обновлений , чтобы убедиться, что вы используете последние версии Android Studio и Firebase Assistant.
  2. Выберите « Инструменты » > « Firebase », чтобы открыть панель « Помощник ».

e791bed0999db1e0.png

  1. Выберите «Мониторинг производительности» , чтобы добавить его в свое приложение, затем нажмите «Начать мониторинг производительности» .
  2. Нажмите « Подключиться к Firebase », чтобы подключить проект Android к Firebase (это откроет консоль Firebase в вашем браузере) .
  3. В консоли Firebase нажмите « Добавить проект» и введите имя проекта Firebase (если у вас уже есть проект Firebase, вы можете вместо этого выбрать этот существующий проект) . Нажмите « Продолжить » и примите условия, чтобы создать проект Firebase и новое приложение Firebase.
  4. Затем вы должны увидеть диалоговое окно для подключения вашего нового приложения Firebase к вашему проекту Android Studio.

42c498d28ead2b77.png

  1. Вернувшись в Android Studio, на панели Assistant вы должны увидеть подтверждение того, что ваше приложение подключено к Firebase.

dda8bdd9488167a0.png

Добавьте мониторинг производительности в свое приложение

На панели « Помощник » в Android Studio нажмите «Добавить мониторинг производительности в ваше приложение» .

Вы должны увидеть диалоговое окно « Принять изменения », после чего Android Studio должна синхронизировать ваше приложение, чтобы убедиться, что все необходимые зависимости были добавлены.

9b58145acc4be030.png

Наконец, вы должны увидеть сообщение об успешном завершении на панели Assistant в Android Studio о том, что все зависимости настроены правильно.

aa0d46fc944e0c0b.png

В качестве дополнительного шага включите ведение журнала отладки , следуя инструкциям на шаге «(Необязательно) Включить ведение журнала отладки». Эти же инструкции есть и в общедоступной документации .

3. Запустите приложение

Если вы успешно интегрировали свое приложение с пакетом SDK для мониторинга производительности, теперь проект должен скомпилироваться. В Android Studio нажмите « Выполнить » > «Запустить приложение», чтобы создать и запустить приложение на подключенном устройстве или эмуляторе Android.

В приложении есть две кнопки, которые ведут к соответствующему действию и фрагменту, например:

410d8686b4f45c33.png

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

4. Понимание загрузки Activity или Fragment

На этом этапе мы узнаем, что делает система во время загрузки действия или фрагмента.

Понимание загрузки Activity

Для действия время загрузки определяется как время, начиная с момента создания объекта действия и до полного отображения первого кадра на экране ( это когда ваш пользователь увидит полный пользовательский интерфейс для действия в первый раз). время ). Чтобы измерить, полностью ли отрисовано ваше приложение, вы можете использовать метод reportFullyDrawn() для измерения времени, прошедшего между запуском приложения и полным отображением всех ресурсов и представлений иерархий.

На высоком уровне, когда ваше приложение вызывает startActivity(Intent) , система автоматически выполняет следующие процессы. Для завершения каждого процесса требуется время, что увеличивает продолжительность времени между созданием действия и моментом, когда пользователь видит пользовательский интерфейс для действия на своем экране.

c20d14b151549937.png

Понимание загрузки фрагмента

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

5. Измерьте время загрузки Activity

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

  1. Запустите пользовательскую трассировку кода (с именем TestActivity-LoadTime ) в классе Activity, как только будет создан объект Activity.

TestActivity.java

public class TestActivity extends AppCompatActivity {   
    // TODO (1): Start trace recording as soon as the Activity object is created.
    private final Trace viewLoadTrace = FirebasePerformance.startTrace("TestActivity-LoadTime");

    // ...

}
  1. Переопределите обратный вызов onCreate() и получите представление, добавленное методом setContentView() .
@Override     
public void onCreate(Bundle savedInstanceState) {    
    super.onCreate(savedInstanceState);          

    // Current Activity's main View (as defined in the layout xml file) is inflated after this            
    setContentView(R.layout.activity_test);          

    // ...

    // TODO (2): Get the View added by Activity's setContentView() method.         
    View mainView = findViewById(android.R.id.content);     

    // ...
}
  1. Мы включили реализацию FistDrawListener с двумя обратными вызовами: onDrawingStart() и onDrawingFinish() (подробнее о FirstDrawListener и о том, что может повлиять на его производительность, см. в следующем разделе ниже) . Зарегистрируйте FirstDrawListener в конце обратного вызова onCreate() Activity. Вы должны остановить свой viewLoadTrace в onDrawingFinish() .

TestActivity.java

    // TODO (3): Register the callback to listen for first frame rendering (see
    //  "OnFirstDrawCallback" in FirstDrawListener) and stop the trace when View drawing is
    //  finished.
    FirstDrawListener.registerFirstDrawListener(mainView, new FirstDrawListener.OnFirstDrawCallback() {              
        @Override             
        public void onDrawingStart() {       
          // In practice you can also record this event separately
        }

        @Override             
        public void onDrawingFinish() {
            // This is when the Activity UI is completely drawn on the screen
            viewLoadTrace.stop();             
        }         
    });
  1. Перезапустите приложение. Затем отфильтруйте logcat с помощью « Метрика трассировки журнала ». Нажмите кнопку LOAD ACTIVITY и найдите журналы, как показано ниже:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

🎉 Поздравляем! Вы успешно измерили время загрузки Activity и передали эти данные в Firebase Performance Monitoring. Мы просмотрим записанную метрику в консоли Firebase позже в этой кодовой лаборатории.

Назначение FirstDrawListener

В разделе чуть выше мы зарегистрировали FirstDrawListener . Цель FirstDrawListener — измерить, когда первый кадр начал и закончил отрисовку.

Он реализует ViewTreeObserver.OnDrawListener и переопределяет обратный вызов onDraw() , который вызывается перед отрисовкой дерева представления. Затем он упаковывает результат для предоставления двух служебных обратных вызовов onDrawingStart() и onDrawingFinish() .

Полный код FirstDrawListener можно найти в исходном коде этой лаборатории кода .

6. Измерьте время загрузки фрагмента

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

  1. Переопределите обратный вызов onAttach() и начните запись вашего fragmentLoadTrace . Мы назовем эту трассировку Test-Fragment-LoadTime .

Как объяснялось на предыдущем шаге, объект Fragment можно создать в любое время, но он становится активным только тогда, когда он присоединен к своему основному действию.

TestFragment.java

public class TestFragment extends Fragment {

   // TODO (1): Declare the Trace variable.
   private Trace fragmentLoadTrace;

   @Override
   public void onAttach(@NonNull Context context) {
       super.onAttach(context);

       // TODO (2): Start trace recording as soon as the Fragment is attached to its host Activity.
       fragmentLoadTrace = FirebasePerformance.startTrace("TestFragment-LoadTime");
   }
  1. Зарегистрируйте FirstDrawListener в onViewCreated() . Затем, как и в примере с Activity, остановите трассировку в onDrawingFinish() .

TestFragment.java

@Override
public void onViewCreated(@NonNull View mainView, Bundle savedInstanceState) {
   super.onViewCreated(mainView, savedInstanceState);

   // ...

   // TODO (3): Register the callback to listen for first frame rendering (see
   //  "OnFirstDrawCallback" in FirstDrawListener) and stop the trace when view drawing is
   //  finished.
   FirstDrawListener.registerFirstDrawListener(mainView, new FirstDrawListener.OnFirstDrawCallback() {

       @Override
       public void onDrawingStart() {
           // In practice you can also record this event separately
       }

       @Override
       public void onDrawingFinish() {
           // This is when the Fragment UI is completely drawn on the screen
           fragmentLoadTrace.stop();
       }
   });
  1. Перезапустите приложение. Затем отфильтруйте logcat с помощью « Метрика трассировки журнала ». Нажмите на кнопку LOAD FRAGMENT и найдите журналы, как показано ниже:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

🎉 Поздравляем! Вы успешно измерили время загрузки фрагмента и передали эти данные в Firebase Performance Monitoring. Мы просмотрим записанную метрику в консоли Firebase позже в этой кодовой лаборатории.

7. Понимание рендеринга экрана и что такое Slow/Frozen frame

Рендеринг пользовательского интерфейса — это процесс создания кадра из вашего приложения и его отображения на экране. Чтобы обеспечить плавное взаимодействие пользователя с вашим приложением, ваше приложение должно отображать кадры менее чем за 16 мс, чтобы достичь 60 кадров в секунду ( почему 60 кадров в секунду? ). Если ваше приложение страдает медленным рендерингом пользовательского интерфейса, система будет вынуждена пропускать кадры, и пользователь заметит заикание в вашем приложении. Мы называем это джанк .

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

8. Измерьте медленные/замороженные кадры фрагмента

Мониторинг производительности Firebase автоматически фиксирует медленные / зависшие кадры для действия ( но только если оно с аппаратным ускорением ). Однако в настоящее время эта функция недоступна для фрагментов. Медленные/замороженные кадры фрагмента определяются как медленные/замороженные кадры для всего действия между onFragmentAttached() и onFragmentDetached() в жизненном цикле фрагмента.

Взяв за основу класс AppStateMonitor ( который является частью пакета Performance Monitoring SDK, отвечающего за запись трассировок экрана для Activity ), мы реализовали класс ScreenTrace ( который является частью этого репозитория исходного кода codelab ). Класс ScreenTrace можно подключить к обратному вызову жизненного цикла FragmentManager Activity для захвата медленных/зависших кадров. Этот класс предоставляет два общедоступных API:

  • recordScreenTrace() : Начинает запись трассировки экрана.
  • sendScreenTrace() : останавливает запись трассировки экрана и прикрепляет пользовательские метрики к журналу общего количества, медленных и замороженных кадров.

При присоединении этих пользовательских метрик трассировки экрана для фрагментов могут обрабатываться так же, как трассировки экрана для действия, и могут отображаться вместе с другими трассировками рендеринга экрана на панели мониторинга производительности консоли Firebase.

Вот как записывать трассировки экрана для вашего фрагмента:

  1. Инициализируйте класс ScreenTrace в своем действии, в котором размещен фрагмент.

MainActivity.java

// Declare the Fragment tag
private static final String FRAGMENT_TAG = TestFragment.class.getSimpleName();

// TODO (1): Declare the ScreenTrace variable.
private ScreenTrace screenTrace;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // TODO (2): Initialize the ScreenTrace variable.
    screenTrace = new ScreenTrace(this, FRAGMENT_TAG);

    // ...
}
  1. Когда вы загружаете свой фрагмент, зарегистрируйтесь для FragmentLifecycleCallbacks и переопределите onFragmentAttached() и onFragmentDetached() . Мы сделали это для вас. Вам нужно начать запись трассировки экрана в onFragmentAttached() и остановить запись в onFragmentDetached() .

MainActivity.java

private final FragmentManager.FragmentLifecycleCallbacks fragmentLifecycleCallbacks =
       new FragmentManager.FragmentLifecycleCallbacks() {

           @Override
           public void onFragmentAttached(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull Context context) {
               super.onFragmentAttached(fm, f, context);

               // TODO (3): Start recording the screen traces as soon as the Fragment is
               //  attached to its host Activity.
               if (FRAGMENT_TAG.equals(f.getTag()) && screenTrace.isScreenTraceSupported()) {
                   screenTrace.recordScreenTrace();
               }
           }

           @Override
           public void onFragmentDetached(@NonNull FragmentManager fm, @NonNull Fragment f) {
               super.onFragmentDetached(fm, f);

               // TODO (4): Stop recording the screen traces as soon as the Fragment is
               //  detached from its host Activity.
               if (FRAGMENT_TAG.equals(f.getTag()) && screenTrace.isScreenTraceSupported()) {
                   screenTrace.sendScreenTrace();
               }

               // Unregister Fragment lifecycle callbacks after the Fragment is detached
               fm.unregisterFragmentLifecycleCallbacks(fragmentLifecycleCallbacks);
           }
       };
  1. Перезапустите приложение. Затем нажмите на кнопку LOAD FRAGMENT . Подождите несколько секунд, затем нажмите кнопку « back button » на нижней панели навигации.

Отфильтруйте logcat с помощью « Метрика трассировки журнала », затем найдите журналы, как показано ниже:

I/FirebasePerformance: Logging trace metric: _st_MainActivity-TestFragment (duration: XXXms)

Отфильтруйте logcat с помощью « FireperfViews », затем найдите журналы, как показано ниже:

D/FireperfViews: sendScreenTrace MainActivity-TestFragment, name: _st_MainActivity-TestFragment, total_frames: XX, slow_frames: XX, frozen_frames: XX

🎉 Поздравляем! Вы успешно измерили медленные/замороженные кадры для фрагмента и передали эти данные в Firebase Performance Monitoring. Мы просмотрим записанные метрики в консоли Firebase позже в этой кодовой лаборатории.

9. Проверяйте метрики в консоли Firebase

  1. В logcat щелкните URL-адрес консоли Firebase, чтобы перейти на страницу сведений для трассировки. ceb9d5ba51bb6e89.jpeg

Либо в консоли Firebase выберите проект, в котором есть ваше приложение. На левой панели найдите раздел « Выпуск и мониторинг », затем нажмите «Производительность» .

  • На главной вкладке Dashboard прокрутите вниз до таблицы трассировок, затем щелкните вкладку Пользовательские трассировки . В этой таблице вы увидите пользовательские трассировки кода, которые мы добавили ранее, а также некоторые готовые трассировки , такие как трассировка _app_start .
  • Найдите две пользовательские трассировки кода, TestActivity-LoadTime и TestFragment-LoadTime . Щелкните Продолжительность для любого из них, чтобы просмотреть дополнительные сведения о собранных данных.

a0d8455c5269a590.png

  1. На странице сведений о пользовательской трассировке кода отображается информация о продолжительности трассировки (т. е. измеренное время загрузки).

5e92a307b7410d8b.png

  1. Вы также можете просмотреть данные о производительности для пользовательской трассировки экрана.
  • Вернитесь на главную вкладку Dashboard , прокрутите вниз до таблицы трассировок, затем щелкните вкладку Screen rendering . В этой таблице вы увидите пользовательские трассировки экрана, которые мы добавили ранее, а также любые готовые трассировки экрана , такие как трассировка MainActivity .
  • Найдите свою пользовательскую трассировку экрана, MainActivity-TestFragment . Щелкните имя трассы, чтобы просмотреть сводные данные о медленном рендеринге и замороженных кадрах.

ee7890c7e2c28740.png

10. Поздравления

Поздравляем! Вы успешно измерили время загрузки и производительность рендеринга экрана действия и фрагмента с помощью Firebase Performance Monitoring!

Что вы сделали

Что дальше

Firebase Performance предоставляет больше способов измерения производительности вашего приложения, помимо пользовательской трассировки. Он автоматически измеряет время запуска приложения, данные о производительности приложения на переднем плане и в фоновом режиме . Пришло время проверить эти метрики в Firebase Console .

Кроме того, Firebase Performance предлагает автоматический мониторинг сетевых запросов HTTP/S . Благодаря этому вы можете легко обрабатывать сетевые запросы, не написав ни единой строки кода. Можете ли вы попробовать отправить несколько сетевых запросов из своего приложения и найти метрики в консоли Firebase ?

Бонус

Теперь, когда вы знаете, как измерить время загрузки и производительность рендеринга экрана вашего действия/фрагмента с помощью пользовательских трассировок кода, вы можете изучить нашу базу кода с открытым исходным кодом, чтобы увидеть, можете ли вы зафиксировать эти метрики из коробки для любого действия/фрагмента. это часть приложения? Не стесняйтесь присылать PR, если хотите :-)

11. Бонусное обучение

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

cd61c1495fad7961.png