Novità sul prodotto

Novità della release di dicembre 2025 di Jetpack Compose

Lettura di 6 minuti
Nick Butcher
Product Manager

Oggi, la release di dicembre 2025 di Jetpack Compose è stabile. Contiene la versione 1.10 dei moduli principali di Compose e la versione 1.4 di Material 3 (vedi la mappatura BOM completa), aggiungendo nuove funzionalità e importanti miglioramenti delle prestazioni.

Per utilizzare la release di oggi, esegui l'upgrade della versione della distinta base di Compose a 2025.12.00:

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

Miglioramenti delle prestazioni

Sappiamo che le prestazioni di runtime della tua app sono estremamente importanti per te e per i tuoi utenti, pertanto le prestazioni sono state una priorità assoluta per il team di Compose. Questa release introduce una serie di miglioramenti, che puoi ottenere semplicemente eseguendo l'upgrade all'ultima versione. I nostri benchmark interni di scorrimento mostrano che Compose ora corrisponde al rendimento che otterresti se utilizzassi Views:

janky.png

Benchmark delle prestazioni di scorrimento che confronta Views e Jetpack Compose in diverse versioni di Compose

Composizione sospendibile nel prefetch pigro

La composizione sospendibile nel precaricamento differito è ora attiva per impostazione predefinita. Si tratta di una modifica fondamentale al funzionamento della pianificazione del runtime di Compose, progettata per ridurre significativamente i problemi di scattosità durante i carichi di lavoro UI pesanti.

In precedenza, una volta avviata una composizione, doveva essere eseguita fino al completamento. Se una composizione era complessa, poteva bloccare il thread principale per un periodo di tempo superiore a un singolo frame, causando il blocco dell'interfaccia utente. Con la composizione in pausa, il runtime può ora "mettere in pausa" il suo lavoro se sta per scadere il tempo e riprenderlo nel frame successivo. È particolarmente efficace se utilizzato con il recupero anticipato del layout pigro per preparare i frame in anticipo. Le API CacheWindow del layout Lazy introdotte in Compose 1.9 sono un ottimo modo per precaricare più contenuti e sfruttare la composizione sospendibile per ottenere prestazioni dell'interfaccia utente molto più fluide.

pausable.gif

La composizione sospendibile combinata con il precaricamento differito contribuisce a ridurre i problemi di fluidità

Abbiamo anche ottimizzato le prestazioni altrove, con miglioramenti a Modifier.onPlaced, Modifier.onVisibilityChanged e altre implementazioni di modificatori. Continueremo a investire per migliorare le prestazioni di Compose.

Nuove funzionalità

Fidelizza

Compose offre una serie di API per mantenere e gestire lo stato nei diversi cicli di vita. Ad esempio, remember mantiene lo stato tra le composizioni e rememberSavable/rememberSerializable per mantenerlo durante la ricreazione di attività o processi. retain è una nuova API che si trova tra queste API e che consente di rendere persistenti i valori tra le modifiche alla configurazione senza essere serializzati, ma non tra l'interruzione del processo. Poiché retain non serializza lo stato, puoi rendere persistenti oggetti come espressioni lambda, flussi e oggetti di grandi dimensioni come bitmap, che non possono essere serializzati facilmente. Ad esempio, puoi utilizzare retain per gestire un lettore multimediale (come ExoPlayer) per assicurarti che la riproduzione dei contenuti multimediali non venga interrotta da una modifica della configurazione.

@Composable

fun MediaPlayer() {

    val applicationContext = LocalContext.current.applicationContext

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

    ...

}

Vogliamo ringraziare la community AndroidDev (in particolare il team di Circuit), che ha influenzato e contribuito alla progettazione di questa funzionalità.

Materiale 1.4

La versione 1.4.0 della libreria material3 aggiunge una serie di nuovi componenti e miglioramenti:

centered-hero-carousel.webp

Carosello hero orizzontale centrato

Tieni presente che le API Material 3 Expressive continuano a essere sviluppate nelle release alpha della libreria material3. Per saperne di più, guarda questo recente intervento:

Nuove funzionalità di animazione

Continuiamo a espandere le nostre API di animazione, inclusi gli aggiornamenti per la personalizzazione delle animazioni degli elementi condivisi.

Elementi condivisi dinamici

Per impostazione predefinita, le animazioni sharedElement() e sharedBounds() tentano di animare

le modifiche al layout ogni volta che viene trovata una chiave corrispondente nello stato di destinazione. Tuttavia, potresti voler disabilitare questa animazione in modo dinamico in base a determinate condizioni, ad esempio la direzione di navigazione o lo stato attuale dell'interfaccia utente.

Per controllare se si verifica la transizione degli elementi condivisi, ora puoi personalizzare SharedContentConfig passato a rememberSharedContentState(). La proprietà isEnabled determina se l'elemento condiviso è attivo.

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

                }

            }

}

Per saperne di più, consulta la documentazione.

Modifier.skipToLookaheadPosition()

In questa release è stato aggiunto un nuovo modificatore, Modifier.skipToLookaheadPosition(), che mantiene la posizione finale di un elemento componibile durante l'esecuzione di animazioni di elementi condivisi. Ciò consente di eseguire transizioni come l'animazione di tipo "rivela", come si può vedere nell'esempio di Androidify con la rivelazione progressiva della fotocamera. Per saperne di più, guarda questo suggerimento video: 

Velocità iniziale nelle transizioni degli elementi condivisi

Questa release aggiunge una nuova API per la transizione degli elementi condivisi, prepareTransitionWithInitialVelocity, che consente di passare una velocità iniziale (ad es. da un gesto) a una transizione degli elementi condivisi:

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 transizione degli elementi condivisi che inizia con una velocità iniziale da un gesto

Transizioni velate

EnterTransitionExitTransition definiscono la modalità di visualizzazione o scomparsa di un AnimatedVisibility/AnimatedContent componibile. Una nuova opzione di velatura sperimentale consente di specificare un colore per velare o coprire i contenuti, ad esempio sfumando un livello nero semi-opaco sui contenuti:

veil_2.gif

Contenuti animati velati: nota il velo (o scrim) semiopaco sui contenuti della griglia durante l'animazione

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

    ...

}

Modifiche imminenti

Ritiro di Modifier.onFirstVisible

Compose 1.9 ha introdotto Modifier.onVisibilityChangedModifier.onFirstVisible. Dopo aver esaminato il tuo feedback, è diventato evidente che il contratto di Modifier.onFirstVisible non era possibile rispettarlo in modo deterministico, in particolare quando un elemento first diventa visibile. Ad esempio, un layout pigro potrebbe eliminare gli elementi che scorrono fuori dalla finestra e ricomporli se tornano in visualizzazione. In questo caso, il callback onFirstVisible verrà attivato di nuovo, in quanto si tratta di un elemento appena composto. Un comportamento simile si verifica anche quando si torna a una schermata visitata in precedenza contenente onFirstVisible. Per questo motivo, abbiamo deciso di ritirare questo modificatore nella prossima release di Compose (1.11) e consigliamo di eseguire la migrazione a onVisibilityChanged. Per saperne di più, consulta la documentazione.

Dispatch di coroutine nei test

Abbiamo intenzione di modificare l'invio delle coroutine nei test per migliorare l'instabilità dei test e rilevare più problemi. Attualmente, i test utilizzano UnconfinedTestDispatcher, che differisce dal comportamento di produzione; ad esempio, gli effetti potrebbero essere eseguiti immediatamente anziché essere messi in coda. In una release futura, prevediamo di introdurre una nuova API che utilizzi StandardTestDispatcher per impostazione predefinita per corrispondere ai comportamenti di produzione. Puoi provare il nuovo comportamento ora nella versione 1.10:

@get:Rule // also createAndroidComposeRule, createEmptyComposeRule

val rule = createComposeRule(effectContext = StandardTestDispatcher())

L'utilizzo di StandardTestDispatcher mette in coda le attività, quindi devi utilizzare meccanismi di sincronizzazione come composeTestRule.waitForIdle() o composeTestRule.runOnIdle(). Se il test utilizza runTest, devi assicurarti che runTest e la regola di composizione condividano la stessa istanza di StandardTestDispatcher per la sincronizzazione.

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

}

Strumenti

Le API di qualità meritano strumenti di qualità e Android Studio ha aggiunto di recente diverse funzionalità per gli sviluppatori di Compose:

Per vedere questi strumenti in azione, guarda questa recente dimostrazione:

Buona composizione

Continuiamo a investire in Jetpack Compose per fornirti le API e gli strumenti necessari per creare UI belle e ricche. Il tuo contributo è molto importante per noi, quindi condividi il tuo feedback su queste modifiche o su ciò che vorresti vedere in futuro nel nostro strumento di monitoraggio dei problemi.

Continua a leggere