1. Прежде чем начать
В этом практическом занятии показано, как создавать базовые профили для оптимизации производительности вашего приложения и как проверить преимущества использования базовых профилей с точки зрения производительности.
Что вам понадобится
- Android Studio Hedgehog (2023.1.1 или более поздняя версия)
- Android Gradle Plugin 8.0 или выше
- Базовое понимание Jetpack Macrobenchmark
- Физическое устройство Android с операционной системой Android 7 (уровень API 24) или выше.
Что вы будете делать
- Настройте проект для использования генераторов базовых профилей.
- Создайте базовые профили для оптимизации запуска приложения и производительности прокрутки.
- Проверьте прирост производительности с помощью библиотеки Jetpack Macrobenchmark.
Что вы узнаете
- Базовые профили и способы их улучшения для повышения производительности приложения.
- Как создать базовые профили.
- Повышение производительности базовых профилей.
2. Настройка
Для начала клонируйте репозиторий Github из командной строки, используя следующую команду:
$ git clone https://github.com/android/codelab-android-performance.git
В качестве альтернативы вы можете скачать два ZIP-файла:
Откройте проект в Android Studio
- В окне «Добро пожаловать в Android Studio» выберите
Откройте существующий проект . - Выберите папку
[Download Location]/codelab-android-performance/baseline-profiles. Убедитесь, что вы выбрали каталогbaseline-profiles. - После импорта проекта в Android Studio убедитесь, что вы можете запустить модуль
app, чтобы собрать пример приложения, с которым вы будете работать позже.
Пример приложения
В этом практическом занятии вы будете работать с примером приложения JetSnack . Это виртуальное приложение для заказа закусок, использующее Jetpack Compose.
Для оценки производительности приложения необходимо понимать структуру пользовательского интерфейса и его поведение, чтобы иметь возможность получить доступ к элементам интерфейса из бенчмарков. Запустите приложение и ознакомьтесь с основными экранами, заказав закуски. Вам не нужно знать подробности архитектуры приложения.

3. Что такое базовые профили?
Базовые профили повышают скорость выполнения кода примерно на 30% с момента первого запуска, избегая этапов интерпретации и JIT- компиляции для включенных участков кода. Благодаря включению базового профиля в приложение или библиотеку, среда выполнения Android (ART) может оптимизировать включенные участки кода с помощью компиляции Ahead of Time (AOT), обеспечивая повышение производительности для каждого нового пользователя и при каждом обновлении приложения. Эта оптимизация на основе профилей (PGO) позволяет приложениям оптимизировать запуск, уменьшить задержки взаимодействия и улучшить общую производительность во время выполнения для конечных пользователей с первого запуска.
Благодаря базовому профилю все взаимодействия пользователя — такие как запуск приложения, навигация между экранами или прокрутка контента — становятся более плавными с первого же запуска. Повышение скорости и отзывчивости приложения приводит к увеличению числа ежедневно активных пользователей и повышению среднего показателя повторных посещений.
Базовые профили помогают оптимизировать приложение не только при запуске, но и в дальнейшем, предоставляя информацию о типичных взаимодействиях пользователя, что улучшает время выполнения приложения с первого запуска. Управляемая AOT-компиляция не зависит от пользовательских устройств и может быть выполнена один раз для каждого релиза на машине разработчика, а не на мобильном устройстве. Благодаря включению базового профиля в релизы, оптимизация приложения становится доступной гораздо быстрее, чем при использовании только облачных профилей .
При отсутствии базового профиля весь код приложения компилируется JIT-компилятором в памяти после интерпретации или в файл odex в фоновом режиме, когда устройство находится в режиме ожидания. В результате пользователи могут столкнуться с неоптимальным взаимодействием с приложением после его первой установки или обновления, пока не будут оптимизированы новые пути.
4. Настройка модуля генератора базового профиля.
Вы можете создавать базовые профили с помощью класса инструментальных тестов, для чего требуется добавить в проект новый модуль Gradle. Самый простой способ добавить его в проект — использовать мастер модулей Android Studio, который входит в состав Android Studio Hedgehog или более поздних версий.
Чтобы открыть окно мастера создания нового модуля, щелкните правой кнопкой мыши по вашему проекту или модулю на панели «Проект» и выберите «Создать» > «Модуль» .

В открывшемся окне выберите «Генератор базового профиля» на панели «Шаблоны».

Помимо обычных параметров, таких как имя модуля, имя пакета, язык или язык конфигурации сборки, существуют два нетипичных для нового модуля параметра: целевое приложение и использование управляемого устройства Gradle .
Целевое приложение — это модуль приложения, для которого генерируются базовые профили. Если в вашем проекте несколько модулей приложения, выберите тот, для которого вы хотите запустить генераторы.
Флажок «Использовать управляемое устройство Gradle» устанавливает модуль для запуска генераторов базового профиля на автоматически управляемых эмуляторах Android. Подробнее об управляемых устройствах Gradle можно прочитать в статье «Масштабируйте свои тесты с помощью управляемых устройств Gradle» . Если этот флажок снят, генераторы будут использовать любое подключенное устройство.
После того как вы определите все детали нового модуля, нажмите «Готово» , чтобы продолжить создание модуля.
Изменения, внесенные мастером модуля.
Мастер модулей вносит ряд изменений в ваш проект.
Это добавляет модуль Gradle с именем baselineprofile или любым другим именем, которое вы выберете в мастере.
Этот модуль использует плагин com.android.test , который указывает Gradle не включать его в ваше приложение, поэтому он может содержать только тестовый код или бенчмарки. Он также применяет плагин androidx.baselineprofile , который позволяет автоматизировать генерацию базовых профилей.
Мастер также вносит изменения в выбранный вами целевой модуль приложения. В частности, он применяет плагин androidx.baselineprofile , добавляет зависимость androidx.profileinstaller и добавляет зависимость baselineProfile к только что созданному модулю build.gradle(.kts) :
plugins {
id("androidx.baselineprofile")
}
dependencies {
// ...
implementation("androidx.profileinstaller:profileinstaller:1.3.0")
"baselineProfile"(project(mapOf("path" to ":baselineprofile")))
}
Добавление зависимости androidx.profileinstaller позволяет сделать следующее:
- Проверьте локально повышение производительности сгенерированных базовых профилей.
- Используйте базовые профили в Android 7 (уровень API 24) и Android 8 (уровень API 26), которые не поддерживают облачные профили.
- Используйте базовые профили на устройствах, на которых не установлены сервисы Google Play.
Зависимость baselineProfile(project(":baselineprofile")) сообщает Gradle, из какого модуля ему нужно взять сгенерированные базовые профили.
Теперь, когда проект готов, напишите класс-генератор базовых профилей.
5. Напишите генератор базового профиля.
Обычно базовые профили создаются для типичных сценариев взаимодействия пользователей с вашим приложением.
Мастер создания модулей создает базовый тестовый класс BaselineProfileGenerator , способный генерировать базовый профиль для запуска вашего приложения, и выглядит следующим образом:
@RunWith(AndroidJUnit4::class)
@LargeTest
class BaselineProfileGenerator {
@get:Rule
val rule = BaselineProfileRule()
@Test
fun generate() {
rule.collect("com.example.baselineprofiles_codelab") {
// This block defines the app's critical user journey. This is where you
// optimize for app startup. You can also navigate and scroll
// through your most important UI.
// Start default activity for your app.
pressHome()
startActivityAndWait()
// TODO Write more interactions to optimize advanced journeys of your app.
// For example:
// 1. Wait until the content is asynchronously loaded.
// 2. Scroll the feed content.
// 3. Navigate to detail screen.
// Check UiAutomator documentation for more information about how to interact with the app.
// https://d.android.com/training/testing/other-components/ui-automator
}
}
}
Этот класс использует тестовое правило BaselineProfileRule и содержит один тестовый метод для генерации профиля. Точкой входа для генерации профиля является функция collect() . Она принимает всего два параметра:
-
packageName: имя пакета вашего приложения. -
profileBlock: последний параметр лямбда-функции.
В лямбда-функции profileBlock вы указываете взаимодействия, охватывающие типичные сценарии использования вашего приложения. Библиотека запускает profileBlock несколько раз, собирает информацию о вызванных классах и функциях и генерирует базовый профиль на устройстве с кодом, подлежащим оптимизации.
По умолчанию созданный класс-генератор содержит интерактивные элементы для запуска вашей Activity по умолчанию и ожидает, пока не будет отрисован первый кадр вашего приложения с помощью метода startActivityAndWait() .
Расширьте возможности генератора, добавив пользовательские маршруты.
Как видите, сгенерированный класс также содержит список TODO которые необходимо выполнить для написания дополнительных интерактивных элементов с целью оптимизации сложных сценариев работы вашего приложения. Это рекомендуется для повышения производительности после запуска приложения.
В нашем демонстрационном приложении вы можете определить эти маршруты, выполнив следующие действия:
- Запустите приложение. Это уже частично предусмотрено сгенерированным классом.
- Дождитесь асинхронной загрузки контента.
- Прокрутите список закусок.
- Перейдите к подробной информации о закусках.
Измените генератор, добавив в него описанные функции, охватывающие типичные маршруты, как показано в следующем фрагменте кода:
// ...
rule.collect("com.example.baselineprofiles_codelab") {
// This block defines the app's critical user journey. This is where you
// optimize for app startup. You can also navigate and scroll
// through your most important UI.
// Start default activity for your app.
pressHome()
startActivityAndWait()
// TODO Write more interactions to optimize advanced journeys of your app.
// For example:
// 1. Wait until the content is asynchronously loaded.
waitForAsyncContent()
// 2. Scroll the feed content.
scrollSnackListJourney()
// 3. Navigate to detail screen.
goToSnackDetailJourney()
// Check UiAutomator documentation for more information about how to interact with the app.
// https://d.android.com/training/testing/other-components/ui-automator
}
// ...
Теперь напишите сценарии взаимодействия для каждого из упомянутых сценариев. Вы можете написать их как функцию расширения для MacrobenchmarkScope , чтобы иметь доступ к предоставляемым ею параметрам и функциям. Такой подход позволяет повторно использовать сценарии взаимодействия с бенчмарками для проверки повышения производительности.
Дождитесь асинхронного содержимого
Во многих приложениях при запуске используется асинхронная загрузка, также известная как состояние полного отображения , которая сообщает системе, когда контент загружен и отрисован, и пользователь может с ним взаимодействовать. Ожидание состояния в генераторе ( waitForAsyncContent ) происходит при следующих взаимодействиях:
- Найдите список закусок для кормления.
- Подождите, пока на экране не отобразятся хотя бы некоторые элементы из списка.
fun MacrobenchmarkScope.waitForAsyncContent() {
device.wait(Until.hasObject(By.res("snack_list")), 5_000)
val contentList = device.findObject(By.res("snack_list"))
// Wait until a snack collection item within the list is rendered.
contentList.wait(Until.hasObject(By.res("snack_collection")), 5_000)
}
путешествие по прокручиваемому списку
Для навигации по прокручиваемому списку закусок ( scrollSnackListJourney ) вы можете отслеживать следующие действия:
- Найдите элемент пользовательского интерфейса «Список закусок».
- Настройте поля жестов таким образом, чтобы они не запускали системную навигацию.
- Прокрутите список и подождите, пока интерфейс стабилизируется.
fun MacrobenchmarkScope.scrollSnackListJourney() {
val snackList = device.findObject(By.res("snack_list"))
// Set gesture margin to avoid triggering gesture navigation.
snackList.setGestureMargin(device.displayWidth / 5)
snackList.fling(Direction.DOWN)
device.waitForIdle()
}
Перейти к подробному описанию путешествия
Последний маршрут ( goToSnackDetailJourney ) реализует следующие взаимодействия:
- Найдите список закусок и все подходящие варианты.
- Выберите элемент из списка.
- Нажмите на товар и дождитесь загрузки экрана с подробной информацией. Вы можете воспользоваться тем фактом, что список закусок больше не будет отображаться на экране.
fun MacrobenchmarkScope.goToSnackDetailJourney() {
val snackList = device.findObject(By.res("snack_list"))
val snacks = snackList.findObjects(By.res("snack_item"))
// Select snack from the list based on running iteration.
val index = (iteration ?: 0) % snacks.size
snacks[index].click()
// Wait until the screen is gone = the detail is shown.
device.wait(Until.gone(By.res("snack_list")), 5_000)
}
После того, как вы определите все необходимые взаимодействия для запуска генератора базового профиля, вам нужно указать устройство, на котором он будет работать.
6. Подготовьте устройство для запуска генератора.
Для создания базовых профилей мы рекомендуем использовать эмулятор, например, устройство, управляемое Gradle, или устройство под управлением Android 13 (API 33) или более поздней версии.
Для обеспечения воспроизводимости процесса и автоматизации создания базовых профилей можно использовать Gradle Managed Devices. Gradle Managed Devices позволяет запускать тесты на эмуляторе Android без необходимости вручную запускать и останавливать его. Подробнее о Gradle Managed Devices можно узнать в статье «Масштабируйте свои тесты с помощью Gradle Managed Devices» .
Чтобы определить управляемое устройство Gradle, добавьте его определение в файл build.gradle.kts модуля :baselineprofile , как показано в следующем фрагменте:
android {
// ...
testOptions.managedDevices.devices {
create<ManagedVirtualDevice>("pixel6Api31") {
device = "Pixel 6"
apiLevel = 31
systemImageSource = "aosp"
}
}
}
В данном случае мы используем Android 11 (уровень API 31), и образ системы aosp поддерживает root-доступ.
Далее настройте плагин Gradle Baseline Profile для использования определенного управляемого устройства Gradle. Для этого добавьте имя устройства в свойство managedDevices и отключите useConnectedDevices как показано в следующем фрагменте кода:
android {
// ...
}
baselineProfile {
managedDevices += "pixel6Api31"
useConnectedDevices = false
}
dependencies {
// ...
}
Далее сгенерируйте базовый профиль.
7. Создайте базовый профиль.
Как только устройство будет готово, вы можете создать базовый профиль. Плагин Gradle для создания базовых профилей создает задачи Gradle для автоматизации всего процесса запуска тестового класса-генератора и применения сгенерированных базовых профилей в вашем приложении.
Новый мастер создания модулей создал конфигурацию запуска, позволяющую быстро запускать задачу Gradle со всеми необходимыми параметрами без необходимости переключаться между терминалом и Android Studio.
Для запуска найдите конфигурацию запуска Generate Baseline Profile и нажмите кнопку «Запустить».
.

Задача запускает ранее определенный образ эмулятора. Запустите взаимодействия из тестового класса BaselineProfileGenerator несколько раз, а затем завершите работу эмулятора и передайте результат в Android Studio.
После успешного завершения работы генератора плагин Gradle автоматически помещает сгенерированный baseline-prof.txt в целевое приложение (модуль :app ) в папку src/release/generated/baselineProfile/ .

(Необязательно) Запустите генератор из командной строки.
В качестве альтернативы, вы можете запустить генератор из командной строки. Вы можете использовать задачу, созданную управляемым устройством Gradle :app:generateBaselineProfile . Эта команда запускает все тесты в проекте, определенном зависимостью baselineProfile(project(:baselineProfile)) . Поскольку модуль также содержит бенчмарки для последующей проверки повышения производительности, эти тесты завершаются с предупреждением о невозможности запуска бенчмарков на эмуляторе.
android .testInstrumentationRunnerArguments .androidx.benchmark.enabledRules=BaselineProfile
Для этого вы можете отфильтровать все генераторы базовых профилей с помощью следующего аргумента средства запуска инструментов, и все бенчмарки будут пропущены:
Вся команда выглядит следующим образом:
./gradlew :app:generateBaselineProfile -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile
Распространяйте свое приложение с помощью базовых профилей.
После того, как базовый профиль будет сгенерирован и скопирован в исходный код вашего приложения, соберите производственную версию приложения, как обычно. Вам не нужно ничего дополнительно делать для распространения базовых профилей среди пользователей. Они будут подхвачены плагином Android Gradle во время сборки и включены в ваш AAB или APK. Затем загрузите сборку в Google Play.
При установке или обновлении приложения с предыдущей версии также устанавливается базовый профиль, что обеспечивает более высокую производительность с первого запуска приложения.
На следующем шаге показано, как проверить, насколько улучшается производительность приложения при использовании базовых профилей.
8. (Необязательно) Настройка процесса создания базовых профилей.
Плагин Baseline Profiles для Gradle включает в себя параметры для настройки способа генерации профилей в соответствии с вашими конкретными потребностями. Вы можете изменить поведение с помощью блока конфигурации baselineProfile { } в скриптах сборки.
Блок конфигурации в модуле :baselineprofile влияет на способ запуска генераторов, предоставляя возможность добавлять managedDevices и выбирать, использовать ли useConnectedDevices ) или управляемые устройства Gradle (Gradle Managed devices).
Блок конфигурации в модуле :app определяет, где сохраняются профили и как они генерируются. Вы можете изменить следующие параметры:
-
automaticGenerationDuringBuild: если включено, вы можете сгенерировать базовый профиль при сборке релизной версии для продакшена. Это полезно при сборке в CI перед выпуском приложения. -
saveInSrc: указывает, следует ли сохранять сгенерированные базовые профили в папкеsrc/. В качестве альтернативы, вы можете получить доступ к файлу из папки сборки:baselineprofile. -
baselineProfileOutputDir: определяет, где хранить сгенерированные базовые профили. -
mergeIntoMain: по умолчанию базовые профили генерируются для каждого варианта сборки (вариант продукта и тип сборки). Если вы хотите объединить все профили вsrc/main, вы можете сделать это, включив этот флаг. -
filter: вы можете отфильтровать, какие классы или методы следует включить или исключить из сгенерированных базовых профилей. Это может быть полезно для разработчиков библиотек, которые хотят включить только код из библиотеки.
9. Проверить улучшения производительности при запуске.
После создания базового профиля и его добавления в приложение убедитесь, что он оказывает желаемое влияние на производительность приложения.
Новый мастер создания модулей создает класс бенчмарка под названием StartupBenchmarks . Он содержит бенчмарк для измерения времени запуска приложения и сравнения его с временем запуска при использовании базовых профилей.
Класс выглядит следующим образом:
@RunWith(AndroidJUnit4::class)
@LargeTest
class StartupBenchmarks {
@get:Rule
val rule = MacrobenchmarkRule()
@Test
fun startupCompilationNone() =
benchmark(CompilationMode.None())
@Test
fun startupCompilationBaselineProfiles() =
benchmark(CompilationMode.Partial(BaselineProfileMode.Require))
private fun benchmark(compilationMode: CompilationMode) {
rule.measureRepeated(
packageName = "com.example.baselineprofiles_codelab",
metrics = listOf(StartupTimingMetric()),
compilationMode = compilationMode,
startupMode = StartupMode.COLD,
iterations = 10,
setupBlock = {
pressHome()
},
measureBlock = {
startActivityAndWait()
// TODO Add interactions to wait for when your app is fully drawn.
// The app is fully drawn when Activity.reportFullyDrawn is called.
// For Jetpack Compose, you can use ReportDrawn, ReportDrawnWhen and ReportDrawnAfter
// from the AndroidX Activity library.
// Check the UiAutomator documentation for more information on how to
// interact with the app.
// https://d.android.com/training/testing/other-components/ui-automator
}
)
}
}
Он использует MacrobenchmarkRule , способный запускать тесты производительности вашего приложения и собирать метрики производительности. Точкой входа для написания теста является функция measureRepeated из правила.
Для этого требуется несколько параметров:
-
packageName:приложение, которое нужно измерить. -
metrics: какой тип информации вы хотите измерить в ходе сравнительного анализа. -
iterations: сколько раз повторяется тест производительности. -
startupMode: как вы хотите, чтобы ваше приложение запускалось при начале тестирования производительности. -
setupBlock: какие взаимодействия с вашим приложением должны произойти перед началом измерений. -
measureBlock: взаимодействия с вашим приложением, которые вы хотите измерить во время бенчмарка.
Класс тестов также содержит два теста: startupCompilationeNone() и startupCompilationBaselineProfiles() , которые вызывают функцию benchmark() с различными compilationMode .
Режим компиляции
Параметр CompilationMode определяет, как приложение будет предварительно скомпилировано в машинный код. Он имеет следующие параметры:
-
DEFAULT: выполняет частичную предварительную компиляцию приложения с использованием базовых профилей, если таковые имеются. Этот параметр используется, если параметрcompilationModeне задан. -
None(): сбрасывает состояние компиляции приложения и не выполняет предварительную компиляцию. Компиляция «на лету» (JIT) остается включенной во время выполнения приложения. -
Partial(): выполняет предварительную компиляцию приложения с базовыми профилями или предварительными запусками, или и тем и другим. -
Full(): предварительно компилирует весь код приложения. Это единственный вариант в Android 6 (API 23) и ниже.
Если вы хотите начать оптимизацию производительности своего приложения, вы можете выбрать режим компиляции DEFAULT , поскольку производительность будет аналогична той, что достигается при установке приложения из Google Play. Чтобы сравнить преимущества в производительности, обеспечиваемые базовыми профилями, вы можете сделать это, сравнив результаты режимов компиляции None и Partial .
Измените бенчмарк, чтобы он ожидал появления контента.
Тесты производительности создаются аналогично генераторам базовых профилей путем написания интерактивных сценариев взаимодействия с вашим приложением. По умолчанию созданные тесты ожидают только отрисовки первого кадра — аналогично тому, как это делал BaselineProfileGenerator — поэтому мы рекомендуем улучшить его, чтобы он ожидал асинхронного контента.
Это можно сделать, повторно используя функции расширения, которые вы пишете для генератора. Поскольку этот бенчмарк фиксирует время запуска — с помощью функции StartupTimingMetric() — мы рекомендуем включить здесь только ожидание асинхронного контента, а затем написать отдельный бенчмарк для других пользовательских сценариев, определенных в генераторе.
// ...
measureBlock = {
startActivityAndWait()
// The app is fully drawn when Activity.reportFullyDrawn is called.
// For Jetpack Compose, you can use ReportDrawn, ReportDrawnWhen and ReportDrawnAfter
// from the AndroidX Activity library.
waitForAsyncContent() // <------- Added to wait for async content.
// Check the UiAutomator documentation for more information on how to
// interact with the app.
// https://d.android.com/training/testing/other-components/ui-automator
}
Запустите тесты производительности.
Вы можете запускать тесты производительности так же, как и инструментальные тесты. Вы можете запустить тестовую функцию или весь класс, рядом с которым находится значок в боковой панели.

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

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

На скриншоте видно, что время запуска приложения различается для каждого CompilationMode . Медианные значения приведены в следующей таблице:
timeToInitialDisplay [мс] | timeToFullDisplay [ms] | |
Никто | 202.2 | 818.8 |
Базовые профили | 193.7 | 637.9 |
Улучшение | 4% | 28% |
Разница между режимами компиляции для timeToFullDisplay составляет 180 мс, что примерно на 28% лучше, чем просто использование базового профиля. CompilationNone работает хуже, потому что устройству приходится выполнять большую часть JIT-компиляции во время запуска приложения. Режим CompilationBaselineProfiles работает лучше, потому что частичная компиляция с использованием AOT-компиляции базовых профилей компилирует код, который пользователь, скорее всего, будет использовать, а некритичный код не компилируется предварительно, поэтому его не нужно загружать немедленно.
10. (Необязательно) Проверьте улучшение производительности прокрутки.
Аналогично предыдущему шагу, вы можете измерить и проверить производительность прокрутки. Сначала создайте тестовый класс ScrollBenchmarks с правилом бенчмарка и двумя тестовыми методами, использующими разные режимы компиляции:
@LargeTest
@RunWith(AndroidJUnit4::class)
class ScrollBenchmarks {
@get:Rule
val rule = MacrobenchmarkRule()
@Test
fun scrollCompilationNone() = scroll(CompilationMode.None())
@Test
fun scrollCompilationBaselineProfiles() = scroll(CompilationMode.Partial())
private fun scroll(compilationMode: CompilationMode) {
// TODO implement
}
}
Внутри метода scroll используйте функцию measureRepeated с необходимыми параметрами. В качестве параметра metrics используйте FrameTimingMetric , которая измеряет время, необходимое для создания кадров пользовательского интерфейса:
private fun scroll(compilationMode: CompilationMode) {
rule.measureRepeated(
packageName = "com.example.baselineprofiles_codelab",
metrics = listOf(FrameTimingMetric()),
compilationMode = compilationMode,
startupMode = StartupMode.WARM,
iterations = 10,
setupBlock = {
// TODO implement
},
measureBlock = {
// TODO implement
}
)
}
На этот раз необходимо более тщательно разделить взаимодействие между блоками setupBlock и measureBlock , чтобы измерять только длительность кадров во время первого отображения макета и прокрутки контента. Поэтому функции, запускающие экран по умолчанию, следует поместить в setupBlock , а уже созданные функции расширения waitForAsyncContent() и scrollSnackListJourney() — в блок measureBlock .
private fun scroll(compilationMode: CompilationMode) {
rule.measureRepeated(
packageName = "com.example.baselineprofiles_codelab",
metrics = listOf(FrameTimingMetric()),
compilationMode = compilationMode,
startupMode = StartupMode.WARM,
iterations = 10,
setupBlock = {
pressHome()
startActivityAndWait()
},
measureBlock = {
waitForAsyncContent()
scrollSnackListJourney()
}
)
}
Как только тест будет готов, вы можете запустить его, как и раньше, чтобы получить результаты, показанные на следующем скриншоте:

Параметр FrameTimingMetric выводит длительность кадров в миллисекундах ( frameDurationCpuMs ) для 50-го, 90-го, 95-го и 99-го процентилей. На Android 12 (уровень API 31) и выше он также возвращает, на сколько времени ваши кадры превышают лимит ( frameOverrunMs ). Значение может быть отрицательным, что означает, что оставалось дополнительное время для создания кадра.
Из результатов видно, что у CompilationBaselineProfiles в среднем на 2 мс короче длительность кадра, что может быть незаметно для пользователей. Однако для других процентилей результаты более очевидны. Для P99 разница составляет 43,5 мс , что более чем на 3 пропущенных кадра больше на устройстве, работающем со скоростью 90 кадров в секунду. Например, для Pixel 6 это 1000 мс / 90 FPS = ~11 мс максимальное время рендеринга кадра.
11. Поздравляем!
Поздравляем, вы успешно завершили этот практический урок и улучшили производительность своего приложения с помощью базовых профилей!
Дополнительные ресурсы
См. следующие дополнительные ресурсы:
- Проанализируйте производительность приложения с помощью Macrobenchmark : это практическое руководство, которое более подробно рассматривает вопросы бенчмаркинга.
- Примеры производительности : репозиторий, содержащий Macrobenchmark и другие примеры производительности.
- Приложение Now In Android — пример реального приложения, использующего бенчмаркинг и базовые профили для повышения производительности.