1. Введение
Последнее обновление: 11.03.2021
Зачем нам измерять производительность Views?
Представления (Views) — ключевая часть Android-приложений, напрямую влияющая на пользовательский опыт. Например, ваша Activity или Fragment содержит пользовательский интерфейс, в котором размещаются компоненты View, с которыми взаимодействуют пользователи. Пользователи не могут увидеть всё содержимое интерфейса, пока оно полностью не отобразится на экране. Медленная и зависшая работа экрана напрямую ухудшает взаимодействие пользователя с вашим приложением и создаёт негативный пользовательский опыт.
Разве Firebase Performance Monitoring не предоставляет эти показатели производительности «из коробки»?
Firebase Performance Monitoring автоматически собирает некоторые данные о производительности, такие как время запуска приложения (т.е. время загрузки только первой Activity) и производительность отрисовки экрана (т.е. медленные и зависшие кадры для Activity, но не для Fragment). Однако в отраслевых приложениях обычно не так много Activity, а скорее одна Activity и несколько Fragment. Кроме того, многие приложения обычно реализуют собственные пользовательские представления (Custom Views) для более сложных сценариев использования. Поэтому часто полезно понимать, как измерить время загрузки и производительность отрисовки экрана как для Activity, так и для Fragment, используя пользовательские трассировки кода в вашем приложении. Вы можете легко расширить этот пример, чтобы измерить производительность компонентов Custom View.
Что вы узнаете
- Как добавить мониторинг производительности Firebase в 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.
- Перейдите в Android Studio / Справка > Проверить наличие обновлений , чтобы убедиться, что вы используете последние версии Android Studio и Firebase Assistant.
- Чтобы открыть панель «Помощник» , выберите «Инструменты» > «Firebase» .

- Выберите пункт «Мониторинг производительности» , который хотите добавить в свое приложение, затем нажмите « Начать работу с мониторингом производительности» .
- Нажмите кнопку, чтобы создать новый проект, а затем введите название проекта (например,
Measure Performance Codelab). - Нажмите «Продолжить» .
- Если появится запрос, ознакомьтесь с условиями использования Firebase и примите их, после чего нажмите «Продолжить» .
- (Необязательно) Включите помощь ИИ в консоли Firebase (в Firebase она называется "Gemini").
- Для этого практического занятия вам не понадобится Google Analytics, поэтому отключите эту опцию.
- Далее вы увидите диалоговое окно для подключения вашего нового приложения Firebase к проекту Android Studio.

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

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

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

В качестве дополнительного шага включите отладочное логирование , следуя инструкциям в шаге "(Необязательно) Включить отладочное логирование". Эти же инструкции также доступны в общедоступной документации .
3. Запустите приложение
Если вы успешно интегрировали свое приложение с SDK мониторинга производительности, проект теперь должен скомпилироваться. В Android Studio нажмите «Запуск» > «Запустить приложение» , чтобы собрать и запустить приложение на подключенном устройстве Android/эмуляторе.
В приложении есть две кнопки, которые позволяют перейти к соответствующему Activity и Fragment, вот так:

В следующих шагах этого практического занятия вы узнаете, как измерить время загрузки и производительность отрисовки экрана вашего Activity или Fragment.
4. Понимание процесса загрузки Activity или Fragment.
На этом этапе мы узнаем, что делает система во время загрузки Activity или Fragment.
Понимание процесса загрузки активности
Для Activity время загрузки определяется как время, начиная с момента создания объекта Activity и до полной отрисовки первого кадра на экране ( именно тогда пользователь впервые увидит полный пользовательский интерфейс Activity ). Чтобы измерить, полностью ли отрисовано ваше приложение, вы можете использовать метод reportFullyDrawn() для измерения времени, прошедшего между запуском приложения и полным отображением всех ресурсов и иерархий представлений.
В общих чертах, когда ваше приложение вызывает startActivity(Intent) , система автоматически выполняет следующие процессы. Каждый процесс занимает время, что увеличивает промежуток времени между созданием Activity и появлением пользовательского интерфейса Activity на экране.

Понимание процесса загрузки фрагмента
Подобно Activity, время загрузки Fragment определяется как время, начинающееся с момента присоединения Fragment к родительской Activity и заканчивающееся полной отрисовкой первого кадра Fragment View на экране.
5. Измерьте время загрузки действия.
Задержки в первом кадре могут привести к негативному пользовательскому опыту, поэтому важно понимать, какую задержку при первоначальной загрузке испытывают ваши пользователи. Вы можете использовать инструмент трассировки пользовательского кода для измерения этого времени загрузки:
- Запустите пользовательскую трассировку кода (с именем
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");
// ...
}
- Переопределите функцию обратного вызова
onCreate()и получите добавленный View с помощью метода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);
// ...
}
- Мы включили реализацию
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();
}
});
- Перезапустите приложение. Затем отфильтруйте 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. Измерьте время загрузки фрагмента.
Измерение времени загрузки фрагмента аналогично измерению времени загрузки активности, но с некоторыми незначительными отличиями. Опять же, мы будем использовать собственную трассировку кода :
- Переопределите функцию обратного вызова
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");
}
- Зарегистрируйте
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();
}
});
- Перезапустите приложение. Затем отфильтруйте logcat по метрике "Трассировка логов ". Нажмите кнопку "
LOAD FRAGMENT" и найдите записи логов, подобные приведенным ниже:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)
🎉 Поздравляем! Вы успешно измерили время загрузки фрагмента и передали эти данные в Firebase Performance Monitoring. Мы посмотрим записанные метрики в консоли Firebase позже в этом практическом занятии.
7. Понимание рендеринга экрана и что такое медленный/замороженный кадр.
Рендеринг пользовательского интерфейса — это процесс генерации кадра из вашего приложения и его отображения на экране. Чтобы обеспечить плавное взаимодействие пользователя с вашим приложением, оно должно рендерить кадры менее чем за 16 мс, чтобы достичь 60 кадров в секунду ( почему 60 кадров в секунду? ). Если ваше приложение страдает от медленного рендеринга пользовательского интерфейса, система вынуждена пропускать кадры, и пользователь будет ощущать подтормаживания. Мы называем это «рывками» .
Аналогично, зависшие кадры — это кадры пользовательского интерфейса, отрисовка которых занимает более 700 мс. Эта задержка является проблемой, поскольку ваше приложение выглядит зависшим и не реагирует на ввод пользователя почти целую секунду, пока отрисовывается кадр.
8. Измерьте количество замедленных/замороженных кадров фрагмента.
Система мониторинга производительности Firebase автоматически фиксирует медленные/зависшие кадры для Activity ( но только если она использует аппаратное ускорение ). Однако в настоящее время эта функция недоступна для Fragment. Медленные/зависшие кадры для Fragment определяются как медленные/зависшие кадры для всего Activity между вызовами onFragmentAttached() и onFragmentDetached() в жизненном цикле Fragment.
Вдохновившись классом AppStateMonitor ( который является частью SDK мониторинга производительности и отвечает за запись трассировки экрана для Activity ), мы реализовали класс ScreenTrace ( который находится в репозитории исходного кода этой лабораторной работы ). Класс ScreenTrace можно подключить к коллбэку жизненного цикла FragmentManager Activity для захвата медленных/зависших кадров. Этот класс предоставляет два публичных API:
-
recordScreenTrace(): Начинает запись трассировки экрана -
sendScreenTrace(): Останавливает запись трассировки экрана и добавляет пользовательские метрики для регистрации общего количества кадров, кадров, отображаемых как медленные, так и зависшие.
Благодаря добавлению этих пользовательских метрик, трассировка экрана для фрагментов может обрабатываться так же, как и трассировка экрана для Activity, и отображаться вместе с другими трассировками отрисовки экрана на панели мониторинга производительности в консоли Firebase.
Вот как записывать трассировку экрана для вашего фрагмента:
- Инициализируйте класс
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);
// ...
}
- При загрузке фрагмента зарегистрируйте
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);
}
};
- Перезапустите приложение. Затем нажмите кнопку
LOAD FRAGMENT. Подождите несколько секунд, затем нажмитеback buttonна нижней панели навигации.
Отфильтруйте logcat по метрике "Logging trace metric ", затем найдите записи, похожие на приведенные ниже:
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.
- В logcat щелкните URL-адрес консоли Firebase, чтобы перейти на страницу с подробной информацией и трассировкой.

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

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

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

10. Поздравляем!
Поздравляем! Вы успешно измерили время загрузки и производительность отрисовки экрана Activity и Fragment с помощью Firebase Performance Monitoring!
Чего вы достигли
- Вы интегрировали Firebase Performance Monitoring в тестовое приложение.
- Теперь вы понимаете жизненный цикл загрузки представления.
- Вы измерили время загрузки как Activity, так и Fragment, добавив пользовательские трассировки кода .
- Вы зафиксировали медленные/зависшие кадры, добавив пользовательские трассировки экрана с пользовательскими метриками.
Что дальше?
Firebase Performance предоставляет больше способов измерения производительности вашего приложения, помимо пользовательской трассировки. Он автоматически измеряет время запуска приложения, производительность приложения в фоновом и переднем режимах . Пришло время проверить эти метрики в консоли Firebase .
Кроме того, Firebase Performance предлагает автоматический мониторинг сетевых запросов HTTP/S . Благодаря этому вы можете легко отслеживать сетевые запросы, не написав ни одной строки кода. Можете попробовать отправить несколько сетевых запросов из своего приложения и посмотреть метрики в консоли Firebase ?
Бонус
Теперь, когда вы знаете, как измерить время загрузки и производительность отрисовки экрана вашего Activity/Fragment с помощью трассировки пользовательского кода, можете ли вы изучить нашу открытую кодовую базу , чтобы посмотреть, можно ли получить эти метрики «из коробки» для любого Activity/Fragment, входящего в состав приложения? Не стесняйтесь отправлять запросы на слияние (PR), если хотите :-)
11. Дополнительное обучение
Понимание того, что происходит во время загрузки Activity, поможет вам лучше понять характеристики производительности вашего приложения. На предыдущем шаге мы в общих чертах описали, что происходит во время загрузки Activity, но следующая диаграмма описывает каждый этап гораздо подробнее.
