Когда в Android запускается анимация, частота обновления экрана обычно увеличивается до максимальной, чтобы обеспечить плавность. Для небольших анимаций, таких как индикаторы выполнения и визуализаторы звука, такая высокая частота обновления не требуется и приводит к высокому энергопотреблению.
Начиная с Android 15, функция адаптивной частоты обновления (ARR) позволяет устройствам реже использовать высокую частоту обновления двумя способами:
- Благодаря новым оптимизациям управления частотой кадров приложения могут по умолчанию использовать более низкую частоту кадров и повышать ее только при необходимости.
- Частота обновления экрана динамически подстраивается под частоту отрисовки контента без задержек.
Большинство приложений могут использовать ARR без изменений, но при необходимости вы можете переопределить поведение частоты кадров по умолчанию.
В этой статье рассматриваются следующие темы:
- Как определяется частота кадров для каждого представления.
- Общие правила, по которым ARR определяет частоту кадров.
- Как вручную переопределить частоту кадров по умолчанию.
Механизм голосования за просмотры
В системе View на Android каждый элемент View в иерархии пользовательского интерфейса может выражать свою предпочтительную частоту кадров. Эти предпочтения собираются и объединяются, чтобы определить окончательную частоту кадров для каждого кадра. Это достигается за счет механизма голосования, в котором каждое представление голосует на основе своего атрибута частоты кадров, который может быть категорией или конкретной частотой. Представления обычно голосуют при отрисовке или обновлении. На основе этих голосов определяется окончательная частота кадров, которая затем отправляется на нижний уровень в качестве подсказки для рендеринга.
В настоящее время для большинства представлений по умолчанию используется нормальная частота кадров, которая часто составляет 60 Гц. Для более высокой частоты кадров можно использовать специальные API, чтобы настроить предпочтения, при этом система обычно выбирает самую высокую частоту кадров. Подробнее о том, как использовать эти API, рассказывается в разделе Как задать частоту кадров или категорию. Общие правила, касающиеся частоты кадров, описаны в разделе Общие правила в отношении частоты кадров.
Категории частоты кадров
В классе View есть разные категории частоты кадров, которые можно использовать при голосовании. Ниже приведено описание каждой категории.
REQUESTED_FRAME_RATE_CATEGORY_DEFAULT– это значение можно задать, чтобы вернуться к режиму работы по умолчанию. Оно указывает, что в представлении нет данных о частоте кадров.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE– View не будет влиять на частоту кадров. Это означает, что даже если представление активно, фреймворк не будет учитывать его при определении частоты кадров.REQUESTED_FRAME_RATE_CATEGORY_NORMAL– средняя частота кадров, подходящая для анимаций, которым не требуется высокая частота кадров или плавность. Обычно это 60 Гц или близкое значение.REQUESTED_FRAME_RATE_CATEGORY_HIGH– частота кадров, подходящая для анимаций, которым требуется высокая частота кадров. Это может повысить плавность, но также может увеличить энергопотребление.
View голосует только в том случае, если требуется перерисовка. Итоговая частота кадров определяется по большинству голосов. Например, если все голоса отданы за вариант "Обычный", то будет выбран вариант "Обычный". Если голоса распределились между вариантами "Обычный" и "Высокий", выбирается вариант "Высокий".
Частота кадров
Помимо категорий частоты кадров, в View также можно указать предпочтительную частоту кадров, например 30, 60 или 120 Гц. Если задано несколько частот кадров, итоговая частота кадров определяется по следующим правилам:
- Кратные значения. Если выбранные частоты кадров кратны друг другу, выбирается наибольшее значение. Например, если есть два голоса – 30 Гц и 90 Гц, то в качестве окончательной частоты кадров будет выбрано 90 Гц.
- Не кратные друг другу:
- Если хотя бы один голос выше 60 Гц, он считается высоким.
- Если все голоса за 60 Гц или ниже, то это считается голосом за "Обычную" частоту.
Кроме того, если в настройках указаны и значения, и категории частоты кадров, то итоговая частота отрисовки обычно определяется по более высокому значению. Например, если один голос отдан за 60 Гц, а другой – за "Высокую", или один – за 120 Гц, а другой – за "Обычную", то частота отрисовки обычно устанавливается на уровне 120 Гц.
Помимо голосов от приложения, на нижний уровень могут отправляться другие подсказки от разных компонентов в одном кадре. Многие из них могут исходить от компонентов системного интерфейса, таких как панель уведомлений, строка состояния, панель навигации и т. д. Итоговые значения частоты кадров определяются на основе данных от нескольких компонентов.
Как задать частоту кадров или категорию
В некоторых случаях вам может потребоваться задать предпочитаемую частоту кадров для View. Например, если анимация воспроизводится недостаточно плавно, вы можете установить для View значение High. Кроме того, если поверх видео воспроизводится медленная или статичная анимация (обычно с частотой 24 или 30 Гц), вы можете снизить частоту обновления, чтобы уменьшить энергопотребление.
Вы можете использовать API setRequestedFrameRate() и getRequestedFrameRate(), чтобы задать предпочтительную частоту кадров или категорию для определенного представления.
Kotlin
// Set the preferred frame rate category to a View // set the frame rate category to NORMAL view.requestedFrameRate = View.REQUESTED_FRAME_RATE_CATEGORY_NORMAL // set the frame rate category to HIGH view.requestedFrameRate = View.REQUESTED_FRAME_RATE_CATEGORY_HIGH // reset the frame rate category view.requestedFrameRate = View.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT // Set the preferred frame rate to a View // set the frame rate to 30 view.requestedFrameRate = 30f // set the frame rate to 60 view.requestedFrameRate = 60f // set the frame rate to 120 view.requestedFrameRate = 120f
Java
// Set the preferred frame rate category to a View // set the frame rate category to NORMAL view.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NORMAL); // set the frame rate category to HIGH view.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_HIGH); // reset the frame rate category view.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT); // Set the preferred frame rate to a View // set the frame rate to 30 view.setRequestedFrameRate(30); // set the frame rate to 60 view.setRequestedFrameRate(60); // set the frame rate to 120 view.setRequestedFrameRate(120);
Пример использования приведен в статье TextureView.
Общие правила в отношении ARR
В предыдущем разделе мы говорили, что большинство анимаций по умолчанию отображаются с частотой 60 Гц, поскольку для каждого представления в качестве предпочтительной частоты кадров установлено значение "Нормальная". Однако в некоторых случаях частота кадров увеличивается до высокой, чтобы анимация была более плавной.
Общие правила в отношении ARR:
- Ускорение при касании. Когда обнаруживается событие касания (
MotionEvent.ACTION_DOWN), частота обновления повышается до высокой и остается такой некоторое время после того, как касание прекратилось. Это позволяет поддерживать высокую скорость отклика. - Жесты пролистывания. Они обрабатываются по-другому: частота обновления постепенно снижается по мере замедления скорости пролистывания. Подробную информацию об этом вы найдете в разделе Улучшение прокрутки.
- Запуск приложений и переходы между окнами. Частота обновления также повышается на некоторое время при запуске приложений, инициализации окон и переходах между ними, чтобы обеспечить плавность визуальных эффектов.
- Анимация. Для анимации, включающей движение или изменение размера, автоматически устанавливается более высокая частота обновления, чтобы улучшить плавность при изменении положения или размера View.
SurfaceViewиTextureView. Частота кадров, явно заданная дляTextureViewиSurfaceView, учитывается и применяется соответствующим образом.
Как включить или отключить режим повышенной чувствительности
Вы можете включить или отключить ускорение при касании на уровне Window. По умолчанию, когда пользователь касается экрана и убирает палец, частота отрисовки на некоторое время увеличивается. API setFrameRateBoostOnTouchEnabled() и getFrameRateBoostOnTouchEnabled() позволяют предотвратить увеличение доли отрисовки при касании определенного элемента Window.
Kotlin
// disable touch boost on a Window window.isFrameRateBoostOnTouchEnabled = false // enable touch boost on a Window window.isFrameRateBoostOnTouchEnabled = true // check if touch boost is enabled on a Window val isTouchBoostEnabled = window.isFrameRateBoostOnTouchEnabled
Java
// disable touch boost on a Window window.setFrameRateBoostOnTouchEnabled(false) // enable touch boost on a Window window.setFrameRateBoostOnTouchEnabled(true) // check if touch boost is enabled on a Window window.getFrameRateBoostOnTouchEnabled()
Улучшение прокрутки
Одним из ключевых вариантов использования динамической оптимизации частоты кадров является улучшение прокрутки (броска). Многие приложения в значительной степени полагаются на то, что пользователи проводят пальцем вверх, чтобы просмотреть новый контент. Улучшение прокрутки ARR динамически регулирует частоту обновления по мере замедления жеста пролистывания, постепенно снижая частоту кадров. Это обеспечивает более эффективный рендеринг при сохранении плавной прокрутки.
Это улучшение относится к прокручиваемым компонентам интерфейса, включая ScrollView, ListView и GridView, и может быть недоступно для некоторых пользовательских реализаций.
Прокрутка ARR доступна для RecyclerView и NestedScrollView. Чтобы включить эту функцию в приложении, обновите AndroidX.recyclerview и AndroidX.core до последней версии. Подробная информация приведена в таблице ниже.
Библиотека |
Версия |
|
1.4.0 |
|
1.15.0 |
Как задать информацию о скорости
Если у вас есть собственный прокручиваемый компонент и вы хотите воспользоваться функцией прокрутки, вызывайте setFrameContentVelocity() для каждого кадра при плавной прокрутке или перелистывании. Пример фрагмента кода:
Kotlin
// set the velocity to a View (1000 pixels/Second) view.frameContentVelocity = 1000f // get the velocity of a View val velocity = view.frameContentVelocity
Java
// set the velocity to a View view.setFrameContentVelocity(velocity); // get the velocity of a View final float velocity = view.getFrameContentVelocity()
Другие примеры можно найти в статьях RecyclerView и ScrollView. Чтобы правильно задать скорость, рассчитайте скорость контента (в пикселях в секунду) вручную, если необходимую информацию нельзя получить из Scroller или OverScroller.
Обратите внимание, что если методы setFrameContentVelocity() и getFrameContentVelocity() вызываются для представлений, которые не являются прокручиваемыми компонентами, они не будут иметь никакого эффекта, поскольку движение автоматически запускает повышенную частоту кадров на основе текущих правил.
Информация о скорости имеет решающее значение для корректировки частоты рендеринга. Например, рассмотрим жест смахивания. В начале скорость прокрутки может быть высокой, поэтому для плавности требуется более высокая частота отрисовки. По мере выполнения жеста скорость уменьшается, что позволяет снизить частоту отрисовки.
Как включить или отключить автоматическое применение рекомендаций
Функция ARR включена по умолчанию для повышения энергоэффективности. Вы можете отключить эту функцию, но мы не рекомендуем этого делать, так как приложение будет потреблять больше энергии. Отключать эту функцию рекомендуется только в том случае, если вы столкнулись с проблемами, которые значительно влияют на удобство использования.
Чтобы включить или отключить ARR, используйте API setFrameRatePowerSavingsBalanced() в Window или API isFrameRatePowerSavingsBalanced() в файле styles.xml.
В следующем фрагменте кода показано, как включить или отключить ARR для Window:
Kotlin
// disable ARR on a Window window.isFrameRatePowerSavingsBalanced = false // enable ARR on a Window window.isFrameRatePowerSavingsBalanced = true // check if ARR is enabled on a Window val isAdaptiveRefreshRateEnabled = window.isFrameRatePowerSavingsBalanced
Java
// disable ARR on a Window window.setFrameRatePowerSavingsBalanced(false) // enable ARR on a Window window.setFrameRatePowerSavingsBalanced(true) // check if ARR is enabled on a Window window.isFrameRatePowerSavingsBalanced()
Чтобы отключить ARR через файл styles.xml, добавьте в стиль в файле res/values/styles.xml следующий элемент:
<style name="frameRatePowerSavingsBalancedDisabled">
<item name="android:windowIsFrameRatePowerSavingsBalanced">false</item>
</style>
ARR для Compose
В Compose 1.9 также добавлена поддержка адаптивной частоты обновления.
В системе View вы используете метод setRequestedFrameRate(), чтобы запросить определенную частоту кадров для View. В Compose новый модификатор позволяет
указать частоту кадров для composable-функции. Этот модификатор работает аналогично setRequestedFrameRate() и принимает либо положительное значение частоты кадров (в Гц), либо предопределенную категорию частоты кадров FrameRateCategory.
Ниже приведены сигнатуры API.
Modifier.preferredFrameRate(frameRate: Float)Modifier.preferredFrameRate(frameRateCategory: FrameRateCategory)
В приведенном ниже фрагменте кода новый модификатор частоты кадров (Modifier.requestedFrameRate(120f)) применяется к composable-функции Text. Этот модификатор заставляет composable-функцию Text запрашивать предпочтительную частоту кадров 120 при отрисовке или анимации (например, при изменении непрозрачности):
var targetAlpha by remember { mutableFloatStateOf(1f) }
val alpha by
animateFloatAsState(
targetValue = targetAlpha,
animationSpec = tween(durationMillis = 1000)
)
Button(
onClick = { targetAlpha = if (targetAlpha == 1f) 0.2f else 1f },
modifier =
Modifier.background(LocalContentColor.current.copy(alpha = alpha))
) {
Text(
text = "Click",
color = LocalContentColor.current.copy(alpha = alpha),
modifier = Modifier.preferredFrameRate(120f)
// You can also pass frame rate category such as FrameRateCategory.High to increase the frame rate
)
}
Затем предпочтительные частоты кадров всех composable-функций собираются и объединяются, чтобы определить окончательную частоту кадров для каждого кадра. Подробнее: SetFrameRateSample, SetFrameRateCategorySample.