Novedades de productos

Novedades de la versión de diciembre del 2025 de Jetpack Compose

Lectura de 6 minutos
Nick Butcher
Responsable de producto

Hoy, la versión de diciembre del 2025 de Jetpack Compose es estable. Contiene la versión 1.10 de los módulos principales de Compose y la versión 1.4 de Material 3 (consulta la asignación de BOM completa), que añade nuevas funciones y mejoras de rendimiento importantes.

Para usar la versión de hoy, actualiza la versión de tu BOM de Compose a 2025.12.00:

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

Mejoras de rendimiento

Sabemos que el rendimiento de tiempo de ejecución de tu aplicación es muy importante para ti y tus usuarios, por lo que el rendimiento ha sido una prioridad para el equipo de Compose. Esta versión incluye varias mejoras, y puedes disfrutar de todas ellas actualizando a la versión más reciente. Nuestras métricas internas de desplazamiento muestran que Compose ahora tiene el mismo rendimiento que si usaras Vistas:

janky.png

Comparativa del rendimiento de desplazamiento entre Views y Jetpack Compose en diferentes versiones de Compose

Composición pausable en la precarga diferida

La composición pausable en la precarga diferida ahora está habilitada de forma predeterminada. Se trata de un cambio fundamental en la forma en que el tiempo de ejecución de Compose programa el trabajo, diseñado para reducir significativamente los tirones durante las cargas de trabajo de la interfaz de usuario pesadas.

Antes, una vez que se iniciaba una composición, tenía que completarse. Si una composición era compleja, podía bloquear el hilo principal durante más de un fotograma, lo que provocaba que la interfaz de usuario se quedara bloqueada. Con la composición que se puede pausar, el tiempo de ejecución ahora puede "pausar" su trabajo si se le acaba el tiempo y reanudarlo en el siguiente fotograma. Esto resulta especialmente eficaz cuando se usa con la prefetización de diseño diferido para preparar los fotogramas con antelación. Las APIs CacheWindow de diseño diferido introducidas en Compose 1.9 son una forma estupenda de precargar más contenido y aprovechar la composición pausada para conseguir un rendimiento de la interfaz de usuario mucho más fluido.

pausable.gif

La composición pausable combinada con la precarga diferida ayuda a reducir el jank

También hemos optimizado el rendimiento en otros lugares, con mejoras en Modifier.onPlaced, Modifier.onVisibilityChanged y otras implementaciones de modificadores. Seguiremos invirtiendo en mejorar el rendimiento de Compose.

Nuevas funciones

Retener

Compose ofrece varias APIs para mantener y gestionar el estado en diferentes ciclos de vida. Por ejemplo, remember mantiene el estado en las composiciones y rememberSavable/rememberSerializable lo mantiene en la recreación de actividades o procesos. retain es una nueva API que se encuentra entre estas APIs y que te permite conservar valores en los cambios de configuración sin serializarlos, pero no en caso de finalización del proceso. Como retain no serializa tu estado, puedes conservar objetos como expresiones lambda, flujos y objetos grandes, como mapas de bits, que no se pueden serializar fácilmente. Por ejemplo, puedes usar retain para gestionar un reproductor multimedia (como ExoPlayer) y asegurarte de que la reproducción no se interrumpa por un cambio en la configuración.

  @Composable

fun MediaPlayer() {

    val applicationContext = LocalContext.current.applicationContext

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

    ...

}

Queremos dar las gracias a la comunidad AndroidDev (especialmente al equipo de Circuit), que ha influido en el diseño de esta función y ha contribuido a ella.

Material 1.4

La versión 1.4.0 de la biblioteca material3 añade varios componentes y mejoras:

centered-hero-carousel.webp

Carrusel destacado horizontal centrado

Ten en cuenta que las APIs Material 3 Expressive se siguen desarrollando en las versiones alfa de la biblioteca material3. Para obtener más información, consulta esta charla reciente:

Nuevas funciones de animación

Seguimos ampliando nuestras APIs de animación, incluidas las actualizaciones para personalizar las animaciones de elementos compartidos.

Elementos compartidos dinámicos

De forma predeterminada, las animaciones sharedElement() y sharedBounds() intentan animar

El diseño cambia cada vez que se encuentra una clave coincidente en el estado de destino. Sin embargo, puede que quieras desactivar esta animación de forma dinámica en función de determinadas condiciones, como la dirección de navegación o el estado actual de la interfaz de usuario.

Para controlar si se produce la transición del elemento compartido, ahora puedes personalizar el SharedContentConfig que se pasa a rememberSharedContentState(). La propiedad isEnabled determina si el elemento compartido está activo.

  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

                }

            }

}

Consulta más información en la documentación.

Modifier.skipToLookaheadPosition()

En esta versión se ha añadido un nuevo modificador, Modifier.skipToLookaheadPosition(), que mantiene la posición final de un elemento componible al realizar animaciones de elementos compartidos. Esto permite realizar transiciones como la animación de tipo "revelar", como se puede ver en el ejemplo de Androidify con la revelación progresiva de la cámara. Consulta este vídeo para obtener más información: 

Velocidad inicial en las transiciones de elementos compartidos

En esta versión se añade una nueva API de transición de elementos compartidos, prepareTransitionWithInitialVelocity, que te permite transferir una velocidad inicial (por ejemplo, desde un gesto) a una transición de elementos compartidos:

  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

Una transición de elemento compartido que empieza con una velocidad inicial a partir de un gesto

Transiciones veladas

EnterTransition y ExitTransition definen cómo aparece o desaparece un elemento componible AnimatedVisibility/AnimatedContent. Una nueva opción experimental de velo te permite especificar un color para velar o cubrir contenido. Por ejemplo, puedes hacer que aparezca o desaparezca una capa negra semitransparente sobre el contenido:

veil_2.gif

Contenido animado velado: observa el velo (o gasa) semitransparente que cubre el contenido de la cuadrícula durante la animación

  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 ->

    ...

}

Próximos cambios

Obsolecencia de Modifier.onFirstVisible

Compose 1.9 introdujo Modifier.onVisibilityChanged y Modifier.onFirstVisible. Tras revisar sus comentarios, nos hemos dado cuenta de que no era posible cumplir el contrato de Modifier.onFirstVisible de forma determinista, concretamente, cuando un elemento primero se hace visible. Por ejemplo, un diseño Lazy puede eliminar los elementos que se desplazan fuera de la ventana gráfica y, a continuación, volver a componerlos si se desplazan de nuevo a la vista. En este caso, la retrollamada onFirstVisible se activaría de nuevo, ya que se trata de un elemento recién compuesto. También se produciría un comportamiento similar al volver a una pantalla visitada anteriormente que contenga onFirstVisible. Por este motivo, hemos decidido retirar este modificador en la próxima versión de Compose (1.11) y recomendamos migrar a onVisibilityChanged. Consulta la documentación para obtener más información.

Distribución de corrutinas en pruebas

Tenemos previsto cambiar el envío de corrutinas en las pruebas para mejorar la inestabilidad de las pruebas y detectar más problemas. Actualmente, las pruebas usan UnconfinedTestDispatcher, que es diferente del comportamiento de producción. Por ejemplo, los efectos pueden ejecutarse inmediatamente en lugar de ponerse en cola. En una próxima versión, tenemos previsto introducir una nueva API que utilice StandardTestDispatcher de forma predeterminada para que coincida con los comportamientos de producción. Puedes probar el nuevo comportamiento ahora en la versión 1.10:

  @get:Rule // also createAndroidComposeRule, createEmptyComposeRule

val rule = createComposeRule(effectContext = StandardTestDispatcher())

Al usar StandardTestDispatcher, se pondrán en cola las tareas, por lo que debes usar mecanismos de sincronización como composeTestRule.waitForIdle() o composeTestRule.runOnIdle(). Si tu prueba usa runTest, debes asegurarte de que runTest y tu regla de redacción compartan la misma instancia de StandardTestDispatcher para la sincronización.

  // 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 { /* ... */ }

}

Herramientas

Las APIs geniales merecen herramientas geniales, y Android Studio ha añadido recientemente varias funciones para los desarrolladores de Compose:

Para ver estas herramientas en acción, consulta esta demostración reciente:

¡Feliz composición!

Seguimos invirtiendo en Jetpack Compose para ofrecerte las APIs y las herramientas que necesitas para crear interfaces de usuario atractivas y completas. Valoramos mucho tus comentarios, así que comparte tu opinión sobre estos cambios o lo que te gustaría ver a continuación en nuestro gestor de incidencias.

Escrito por:

Seguir leyendo