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

1. Введение

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

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

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

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

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

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

  • Как добавить мониторинг производительности Firebase в приложение для Android
  • Понимание загрузки действия или фрагмента
  • Как инструментировать трассировки пользовательского кода для измерения времени загрузки действия или фрагмента
  • Понимание рендеринга экрана и что такое медленный/замороженный кадр
  • Как оснастить трассировки пользовательского кода метриками для записи медленных/замороженных экранов
  • Как просмотреть собранные метрики в консоли 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, на панели «Ассистент» вы должны увидеть подтверждение того, что ваше приложение подключено к Firebase.

dda8bdd9488167a0.png

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

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

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

9b58145acc4be030.png

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

aa0d46fc944e0c0b.png

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

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

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

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

410d8686b4f45c33.png

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

4. Понимание загрузки активности или фрагмента

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

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

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

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

c20d14b151549937.png

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

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

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() активности. Вам следует остановить 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)

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

Цель FirstDrawListener

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

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

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

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

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

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

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

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. Понимание рендеринга экрана и что такое медленный/замороженный кадр

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

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

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

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

Взяв за основу класс AppStateMonitor ( который является частью Performance Monitoring SDK, отвечающим за запись трассировок экрана для Activity ), мы реализовали класс ScreenTrace ( который является частью этого репозитория исходного кода codelab ). Класс ScreenTrace можно подключить к обратному вызову жизненного цикла FragmentManager действия для захвата медленных/зависших кадров. Этот класс предоставляет два общедоступных 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. В логарифме щелкните URL-адрес консоли Firebase, чтобы перейти на страницу сведений для трассировки. ceb9d5ba51bb6e89.jpeg

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

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

a0d8455c5269a590.png

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

5e92a307b7410d8b.png

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

ee7890c7e2c28740.png

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

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

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

Что дальше

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

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

Бонус

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

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

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

cd61c1495fad7961.png