Новости о продуктах

Что нового в релизе Jetpack Compose от декабря 2025 года?

6 минут чтения
Nick Butcher
Менеджер по продукту

Сегодня вышла стабильная версия Jetpack Compose December '25 . Она включает в себя версию 1.10 основных модулей Compose и версию 1.4 Material 3 (см. полное сопоставление спецификаций ), добавляя новые функции и значительно улучшая производительность.

Чтобы использовать сегодняшнюю версию, обновите Compose BOM до версии 2025.12.00 :

implementation(platform("androidx.compose:compose-bom:2025.12.00"))

Улучшения производительности

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

janky.png

Сравнительный тест производительности прокрутки, сравнивающий Views и Jetpack Compose в разных версиях Compose.

Приостанавливаемая композиция в режиме отложенной предварительной загрузки

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

Ранее, после начала композиции, она должна была выполняться до конца. Если композиция была сложной, это могло блокировать основной поток дольше, чем на один кадр, вызывая зависание пользовательского интерфейса. Благодаря возможности приостановки композиции, среда выполнения теперь может «приостанавливать» свою работу, если у нее заканчивается время, и возобновлять работу в следующем кадре. Это особенно эффективно при использовании с отложенной предварительной загрузкой макета для подготовки кадров заранее. API-интерфейсы CacheWindow для отложенной компоновки, представленные в Compose 1.9, — это отличный способ предварительной загрузки большего количества контента и использования преимуществ отложенной композиции для обеспечения гораздо более плавной работы пользовательского интерфейса.

pausable.gif

Функция паузируемой композиции в сочетании с отложенной предварительной загрузкой помогают уменьшить задержки.

Мы также оптимизировали производительность в других областях, улучшив Modifier.onPlaced , Modifier.onVisibilityChanged и другие реализации модификаторов. Мы продолжим инвестировать в повышение производительности Compose.

Новые функции

Удерживать

Compose предлагает ряд API для хранения и управления состоянием на разных этапах жизненного цикла; например, remember сохраняет состояние между композициями, а rememberSavable / rememberSerializable — между перезапуском активности или процесса. retain — это новый API, который находится между этими API, позволяя сохранять значения при изменении конфигурации без сериализации, но не при завершении процесса. Поскольку retain не сериализует ваше состояние, вы можете сохранять такие объекты, как лямбда-выражения, потоки и большие объекты, такие как растровые изображения, которые сложно сериализовать. Например, вы можете использовать retain для управления медиаплеером (например, ExoPlayer), чтобы гарантировать, что воспроизведение мультимедиа не будет прервано изменением конфигурации.

@Composable

fun MediaPlayer() {

    val applicationContext = LocalContext.current.applicationContext

    val exoPlayer = retain { ExoPlayer.Builder(applicationContext).apply { ... }.build() }

    ...

}

Мы хотим выразить благодарность сообществу AndroidDev (особенно команде Circuit ), которая повлияла на разработку этой функции и внесла свой вклад в её создание.

Материал 1.4

В версии 1.4.0 библиотеки material3 добавлен ряд новых компонентов и улучшений:

  • TextField теперь доступна экспериментальная версия на основе TextFieldState , которая обеспечивает более надежный способ управления состоянием текста. Кроме того, теперь предлагаются новые варианты SecureTextField и OutlinedSecureTextField . В компоненте Material Text теперь поддерживается поведение autoSize.
  • Компонент карусели теперь предлагает новый вариант HorizontalCenteredHeroCarousel .
  • Теперь TimePicker поддерживает переключение между режимами выбора времени и ввода данных.
  • Вертикальный маркер перетаскивания помогает пользователям изменять размер и/или положение адаптивной панели.
centered-hero-carousel.webp

Горизонтальная центрированная карусель героев

Обратите внимание, что разработка выразительных API Material 3 продолжается в альфа-версиях библиотеки material3 . Для получения дополнительной информации ознакомьтесь с этим недавним докладом:

Новые анимационные функции

Мы продолжаем расширять наши API для анимации, включая обновления для настройки анимации общих элементов.

Динамические общие элементы

По умолчанию анимации sharedElement() и sharedBounds() пытаются выполнить анимацию.

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

Чтобы контролировать, происходит ли переход к общему элементу, теперь можно настроить SharedContentConfig , передаваемый в rememberSharedContentState() . Свойство isEnabled определяет, активен ли общий элемент.

SharedTransitionLayout {

        val transition = updateTransition(currentState)

        transition.AnimatedContent { targetState ->

            // Create the configuration that depends on state changing.

            fun animationConfig() : SharedTransitionScope.SharedContentConfig {

                return object : SharedTransitionScope.SharedContentConfig {

                    override val SharedTransitionScope.SharedContentState.isEnabled: Boolean

                        get() =

                            // determine whether to perform a shared element transition

                }

            }

}

Для получения более подробной информации см. документацию .

Modifier.skipToLookaheadPosition()

В этом релизе добавлен новый модификатор Modifier.skipToLookaheadPosition() , который сохраняет конечное положение составного элемента при выполнении анимации общих элементов. Это позволяет выполнять переходы типа анимации «появление», как это видно в примере Androidify с постепенным раскрытием камеры. Более подробную информацию можно найти в видеоподсказке здесь:

Начальная скорость при переходах между общими элементами

В этом релизе добавлен новый API для перехода между общими элементами, prepareTransitionWithInitialVelocity , который позволяет передавать начальную скорость (например, от жеста) для перехода между общими элементами:

Modifier.fillMaxSize()

    .draggable2D(

        rememberDraggable2DState { offset += it },

        onDragStopped = { velocity ->

            // Set up the initial velocity for the upcoming shared element

            // transition.

            sharedContentStateForDraggableCat

                ?.prepareTransitionWithInitialVelocity(velocity)

            showDetails = false

        },

    )
fling-shared.gif

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

Завуалированные переходы

EnterTransition и ExitTransition определяют, как отображается или исчезает компонент AnimatedVisibility / AnimatedContent . Новая экспериментальная опция «вуаль» позволяет задать цвет для скрытия или затемнения контента; например, плавное появление/исчезновение полупрозрачного черного слоя поверх контента:

veil_2.gif

Анимированный контент, создающий эффект полупрозрачной вуали (или завесы) над содержимым сетки во время анимации.

AnimatedContent(

    targetState = page,

    modifier = Modifier.fillMaxSize().weight(1f),

    transitionSpec = {

        if (targetState > initialState) {

            (slideInHorizontally { it } togetherWith

                    slideOutHorizontally { -it / 2 } + veilOut(targetColor = veilColor))

        } else {

            slideInHorizontally { -it / 2 } +

                    unveilIn(initialColor = veilColor) togetherWith slideOutHorizontally { it }

        }

    },

) { targetPage ->

    ...

}

Предстоящие изменения

Устаревшая функция Modifier.onFirstVisible

В Compose 1.9 были введены Modifier.onVisibilityChanged и Modifier.onFirstVisible . После анализа ваших отзывов стало очевидно, что контракт Modifier.onFirstVisible невозможно соблюдать детерминированно, в частности, когда элемент впервые становится видимым. Например, ленивая компоновка может освобождать ресурсы элементов, которые прокручиваются за пределы области видимости, а затем снова компоновать их, если они прокручиваются обратно в область видимости. В этом случае коллбэк onFirstVisible сработает снова, поскольку это новый компонованный элемент. Аналогичное поведение также будет наблюдаться при возврате на ранее посещенный экран, содержащий onFirstVisible . Поэтому мы решили объявить этот модификатор устаревшим в следующем релизе Compose (1.11) и рекомендуем перейти на onVisibilityChanged . Дополнительную информацию см. в документации .

Выполнение сопрограмм в тестах

Мы планируем изменить диспетчеризацию сопрограмм в тестах, чтобы улучшить нестабильность тестов и выявлять больше проблем. В настоящее время тесты используют UnconfinedTestDispatcher , что отличается от поведения в производственной среде; например, эффекты могут выполняться немедленно, а не ставиться в очередь. В будущем релизе мы планируем ввести новый API, который по умолчанию использует StandardTestDispatcher , чтобы соответствовать поведению в производственной среде. Вы можете попробовать новое поведение уже сейчас в версии 1.10:

@get:Rule // also createAndroidComposeRule, createEmptyComposeRule

val rule = createComposeRule(effectContext = StandardTestDispatcher())

Использование StandardTestDispatcher приводит к постановке задач в очередь, поэтому необходимо использовать механизмы синхронизации, такие как composeTestRule.waitForIdle() или composeTestRule.runOnIdle() . Если ваш тест использует runTest , необходимо убедиться, что runTest и ваше правило Compose используют один и тот же экземпляр StandardTestDispatcher для синхронизации.

// 1. Create a SINGLE dispatcher instance

val testDispatcher = StandardTestDispatcher()



// 2. Pass it to your Compose rule

@get:Rule

val composeRule = createComposeRule(effectContext = testDispatcher)



@Test

// 3. Pass the *SAME INSTANCE* to runTest

fun myTest() = runTest(testDispatcher) {

    composeRule.setContent { /* ... */ }

}

Инструменты

Отличные API заслуживают отличных инструментов, и Android Studio недавно пополнилась рядом новых возможностей для разработчиков, использующих Compose:

Чтобы увидеть эти инструменты в действии, посмотрите эту недавнюю демонстрацию:

Удачного сочинения!

Мы продолжаем инвестировать в Jetpack Compose, чтобы предоставить вам API и инструменты, необходимые для создания красивых и многофункциональных пользовательских интерфейсов. Мы ценим ваше мнение, поэтому, пожалуйста, поделитесь своими отзывами об этих изменениях или о том, что вы хотели бы увидеть в будущем, в нашем трекере задач .

    Автор:

    Продолжить чтение