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

1. Введение

Последнее обновление: 11.03.2021

Зачем нам нужно измерять эффективность просмотров?

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

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

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

Чему вы научитесь

  • Как добавить Firebase Performance Monitoring в приложение Android
  • Понимание загрузки Activity или Fragment
  • Как использовать пользовательские трассировки кода для измерения времени загрузки Activity или Fragment
  • Понимание рендеринга экрана и что такое медленный/замороженный кадр
  • Как инструментировать пользовательские трассировки кода с помощью метрик для регистрации медленных/зависших экранов
  • Как просмотреть собранные метрики в консоли 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
  3. Выберите Performance Monitoring для добавления в свое приложение, затем нажмите Get started with Performance Monitoring .
  4. Нажмите кнопку, чтобы создать новый проект, а затем введите название проекта (например, Measure Performance Codelab ).
  5. Нажмите «Продолжить» .
  6. При появлении соответствующего запроса ознакомьтесь с условиями Firebase и примите их, а затем нажмите кнопку «Продолжить» .
  7. (Необязательно) Включите помощь ИИ в консоли Firebase (так называемая «Gemini в Firebase»).
  8. Для этой лабораторной работы вам не понадобится Google Analytics, поэтому отключите опцию Google Analytics.
  9. Далее вы увидите диалоговое окно для подключения нового приложения Firebase к проекту Android Studio.
    42c498d28ead2b77.png
  10. Вернувшись в Android Studio, на панели Assistant вы должны увидеть подтверждение того, что ваше приложение подключено к Firebase.
    dda8bdd9488167a0.png

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

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

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

9b58145acc4be030.png

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

aa0d46fc944e0c0b.png

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

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

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

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

410d8686b4f45c33.png

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

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

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

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

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

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

c20d14b151549937.png

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

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

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

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

  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. Перезапустите приложение. Затем отфильтруйте данные журнала по параметру « Logging trace metric ». Нажмите кнопку 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. Перезапустите приложение. Затем отфильтруйте данные журнала по параметру « Logging trace metric ». Нажмите кнопку LOAD FRAGMENT и найдите записи журнала, как показано ниже:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

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

7. Понимание рендеринга экрана и что такое медленный/замороженный кадр

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

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

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

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

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

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

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

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

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

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 . На левой панели найдите раздел «Выпуск и мониторинг» и нажмите «Производительность» .

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

a0d8455c5269a590.png

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

5e92a307b7410d8b.png

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

ee7890c7e2c28740.png

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

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

Чего вы достигли?

Что дальше?

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

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

Бонус

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

11. Дополнительное обучение

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

cd61c1495fad7961.png