Gestire le modifiche alla configurazione

Alcune configurazioni del dispositivo possono cambiare mentre l'app è in esecuzione. Questi includono, a titolo esemplificativo:

  • Dimensioni di visualizzazione dell'app
  • Densità schermo (scalabilità del display)
  • Orientamento schermo
  • Dimensioni e spessore del carattere
  • Impostazioni internazionali
  • Tema scuro e tema chiaro
  • Disponibilità della tastiera

La maggior parte di queste modifiche alla configurazione si verifica a causa di un'interazione dell'utente. Ad esempio, la rotazione o la piegatura del dispositivo modifica la quantità di spazio sullo schermo disponibile per la tua app. La connessione a display esterni o lo spostamento di un'app tra display con densità di pixel diverse altera la densità dello schermo e le dimensioni del display. Analogamente, la modifica delle impostazioni del dispositivo, come la scala del display, le dimensioni del carattere, la lingua o il tema preferito, cambia i rispettivi valori nell'oggetto Configuration.

In genere, questi parametri richiedono modifiche alla UI dell'applicazione sufficientemente ampie da richiedere un meccanismo apposito della piattaforma Android per quando cambiano. Questo meccanismo è la ricreazione di Activity.

Attività ricreative

Il sistema ricrea un Activity quando si verifica una modifica della configurazione. Per farlo, il sistema chiama onDestroy ed elimina l'istanza Activity esistente. Quindi crea una nuova istanza utilizzando onCreate e questa nuova istanza Activity viene inizializzata con la nuova configurazione aggiornata. Ciò significa anche che il sistema ricrea la UI con la nuova configurazione.

In genere, Activity funge da host per i componibili. Quando Activity viene ricreata, Compose ricrea anche la UI utilizzando i nuovi valori di configurazione.

Il comportamento di ricreazione aiuta l'applicazione ad adattarsi alle nuove configurazioni ricaricandola automaticamente con risorse alternative che corrispondono alla nuova configurazione del dispositivo.

Esempio di svago

Considera un componibile che mostra un titolo statico utilizzando una risorsa stringa:

// In the res/values/strings.xml file
// <string name="compose">Jetpack Compose</string>

// In your Compose code
Text(
    text = stringResource(R.string.compose)
)

Quando viene creato Activity, l'elemento componibile Text legge la configurazione corrente (ad esempio la lingua) e risolve la risorsa stringa appropriata.

Se la lingua cambia, il sistema ricrea l'attività. In questo caso, Compose ricrea la UI. Poiché stringResource legge dalla configurazione corrente, il titolo viene aggiornato automaticamente al valore localizzato corretto.

La ricreazione cancella anche lo stato conservato come campi in Activity.

Per preservare lo stato della UI durante le modifiche alla configurazione, utilizza i pattern di gestione dello stato consigliati. Utilizza ViewModel per i dati e la logica di business e rememberSaveable per lo stato a livello di UI. Con questi meccanismi, lo stato sopravvive alla ricreazione di Activity mentre la UI si aggiorna per riflettere la nuova configurazione.

Per saperne di più sul salvataggio dello stato in Compose, consulta Salva lo stato della UI in Compose.

Aspettative degli utenti

L'utente di un'app si aspetta che lo stato venga conservato. Se un utente sta compilando un modulo e apre un'altra app in modalità multi-finestra per consultare informazioni, l'esperienza utente è negativa se torna a un modulo vuoto o a un'altra posizione nell'app. In qualità di sviluppatore, devi fornire un'esperienza utente coerente tramite le modifiche alla configurazione e la ricreazione delle attività.

Per verificare se lo stato viene conservato nella tua applicazione, puoi eseguire azioni che causano modifiche alla configurazione sia quando l'app è in primo piano sia quando è in background. Queste azioni includono:

  • Rotazione del dispositivo
  • Attivazione della modalità multi-finestra
  • Ridimensionamento dell'applicazione in modalità multi-finestra o in una finestra in formato libero
  • Chiusura di un dispositivo pieghevole con più display
  • Modifica delle dimensioni di visualizzazione o della scalabilità del display nelle impostazioni di sistema
  • Spostamento dell'app tra display con densità dello schermo diverse (ad esempio monitor esterni collegati o display di un dispositivo pieghevole)
  • Modifica del tema di sistema, ad esempio tema scuro rispetto a tema chiaro
  • Modifica delle dimensioni del carattere
  • Modifica della lingua del sistema o dell'app
  • Collegamento o scollegamento di una tastiera hardware
  • Collegamento o scollegamento di una base

Esistono diversi approcci che puoi adottare per preservare lo stato pertinente durante la ricreazione di Activity. La scelta dipende dal tipo di stato che vuoi conservare:

  • Persistenza locale per gestire l'interruzione del processo per dati complessi o di grandi dimensioni. Lo spazio di archiviazione locale permanente include database o DataStore.
  • Oggetti conservati, come le istanze ViewModel, per gestire lo stato relativo alla UI in memoria mentre l'utente utilizza attivamente l'app.
  • rememberSaveable per conservare lo stato transitorio della UI durante le modifiche alla configurazione e l'interruzione del processo avviata dal sistema. Questo è appropriato per lo stato che dipende dall'input dell'utente, dalla posizione di scorrimento o dalla navigazione, ma non appartiene a un ViewModel.

Per informazioni dettagliate sulle API per ciascuno di questi casi e su quando è opportuno utilizzarle, consulta Salva gli stati della UI.

Limita la ricreazione delle attività

Puoi impedire la ricreazione automatica delle attività per determinate modifiche alla configurazione. Nelle moderne app solo Compose, la UI viene ricomposta in entrambi i casi, ma è consigliabile gestire direttamente la modifica della configurazione.

Per impostazione predefinita, una modifica alla configurazione forza il sistema a distruggere e ricreare l'attività, inclusa l'interfaccia utente e tutti gli oggetti derivati dall'attività. Se dichiari che la tua attività gestisce autonomamente la modifica della configurazione, il sistema lo impedisce. Viene aggiornato solo l'oggetto Configuration e Compose ricompone la UI con i nuovi valori.

La gestione delle modifiche alla configurazione direttamente in Compose offre diversi vantaggi:

  • Prestazioni migliorate: la ricomposizione della UI è meno costosa di un ciclo completo di ricreazione dell'attività, soprattutto per le modifiche minori.
  • Animazioni fluide:evitare il riavvio di un'attività ti consente di eseguire animazioni continue durante le modifiche alla configurazione, ad esempio transizioni fluide del layout durante la rotazione del dispositivo.
  • Conservazione dello stato:la conservazione dell'istanza Activity riduce il rischio di perdita dello stato temporaneo della UI durante un evento come la rotazione dello schermo. Tieni presente che devi comunque gestire la conservazione dello stato per l'interruzione del processo avviata dal sistema.

Per disattivare la ricreazione dell'attività per determinate modifiche alla configurazione, aggiungi il tipo di configurazione a android:configChanges nella voce <activity> nel file AndroidManifest.xml. I valori possibili sono riportati nella documentazione relativa all'attributo android:configChanges.

Il seguente codice manifest disattiva la ricreazione di Activity per MyActivity quando l'orientamento dello schermo e la disponibilità della tastiera cambiano:

<activity
    android:name=".MyActivity"
    android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
    android:label="@string/app_name">

Android 17

A partire da Android 17 (livello API 37), il sistema non riavvia più le attività per impostazione predefinita per diverse modifiche alla configurazione che in genere non richiedono la ricreazione completa della UI. Le attività rimangono attive e ricevono aggiornamenti tramite il callback onConfigurationChanged(). Le modifiche specifiche alla configurazione includono:

Se la tua applicazione si basa su un riavvio completo per ricaricare le risorse per queste modifiche, ora devi attivare esplicitamente il comportamento precedente utilizzando l'attributo android:recreateOnConfigChanges nel file manifest. L'attributo consente di specificare quali modifiche alla configurazione devono attivare un ciclo completo di arresto, distruzione e ricreazione dell'attività, ad esempio:

<activity
    android:name=".MyActivity"
    android:recreateOnConfigChanges="keyboard|keyboardHidden|navigation|colorMode|touchscreen|...">
    ...
</activity>

Reagisci alle modifiche alla configurazione

Jetpack Compose consente alla tua app di reagire più facilmente alle modifiche alla configurazione. Tuttavia, se disattivi la ricreazione di Activity per tutte le modifiche alla configurazione dove è possibile farlo, l'app deve comunque gestire correttamente le modifiche alla configurazione.

L'oggetto Configuration è disponibile nella gerarchia della UI di Compose con la composizione locale LocalConfiguration. Ogni volta che cambia, le funzioni componibili che leggono da LocalConfiguration.current vengono ricomposte. Per informazioni sul funzionamento dei composition local, consulta Dati con ambito locale con CompositionLocal.

Esempio

Nell'esempio seguente, un composable mostra una data con un formato specifico. Il composable reagisce alle modifiche alla configurazione delle impostazioni internazionali del sistema chiamando ConfigurationCompat.getLocales con LocalConfiguration.current.

@Composable
fun DateText(year: Int, dayOfYear: Int) {
    val dateTimeFormatter = DateTimeFormatter.ofPattern(
        "MMM dd",
        ConfigurationCompat.getLocales(LocalConfiguration.current)[0]
    )
    Text(
        dateTimeFormatter.format(LocalDate.ofYearDay(year, dayOfYear))
    )
}

Per evitare la ricreazione di Activity quando cambia la lingua, l'Activity che ospita il codice di Compose deve disattivare le modifiche alla configurazione della lingua. Per farlo, imposta android:configChanges su locale|layoutDirection.

Modifiche alla configurazione: concetti chiave e best practice

Ecco i concetti chiave che devi conoscere quando lavori sulle modifiche alla configurazione:

  • Configurazioni: Le configurazioni dispositivo definiscono il modo in cui la UI viene visualizzata dall'utente, ad esempio le dimensioni di visualizzazione dell'app, la densità dello schermo, le impostazioni internazionali o il tema di sistema. In Compose, puoi accedere ai valori di configurazione utilizzando LocalConfiguration.
  • Modifiche alla configurazione: le configurazioni cambiano tramite l'interazione dell'utente. Ad esempio, l'utente potrebbe modificare le impostazioni del dispositivo o il modo in cui interagisce fisicamente con il dispositivo. Non è possibile impedire le modifiche alla configurazione.
  • Ricreazione di Activity: le modifiche alla configurazione comportano la ricreazione di Activity per impostazione predefinita. Si tratta di un meccanismo integrato per reinizializzare lo stato dell'app per la nuova configurazione.
  • Distruzione di Activity: la ricreazione di Activity fa sì che il sistema distrugga l'istanza Activity precedente e ne crei una nuova al suo posto. La vecchia istanza è ora obsoleta. Evita di conservare i riferimenti agli oggetti con ambito del ciclo di vita oltre l'ambito previsto.
  • Stato: lo stato nella vecchia istanza Activity non è presente nella nuova istanza Activity, perché si tratta di due istanze di oggetti diverse. Anziché associare lo stato all'attività, utilizza le API consigliate per preservare lo stato dell'app e dell'utente, come descritto in Salva gli stati della UI.
  • Disattivazione:la disattivazione della ricreazione dell'attività per un tipo di modifica della configurazione richiede che l'app venga aggiornata correttamente in risposta alla nuova configurazione.

Per offrire un'esperienza utente ottimale, segui queste best practice:

  • Preparati a frequenti modifiche alla configurazione:non dare per scontato che le modifiche alla configurazione siano rare o non si verifichino mai, indipendentemente dal livello API, dal fattore di forma o dal toolkit dell'interfaccia utente. Quando un utente apporta una modifica alla configurazione, si aspetta che le app si aggiornino e continuino a funzionare correttamente con la nuova configurazione.
  • Mantieni lo stato:non perdere lo stato dell'utente quando viene ricreata l'Activity. Conserva lo stato come descritto in Salva gli stati della UI utilizzando API come ViewModel e rememberSaveable.
  • Evita di disattivare la funzionalità come soluzione rapida: non disattivare la ricreazione di Activity come scorciatoia per evitare la perdita di stato. La disattivazione della ricreazione dell'attività richiede di mantenere la promessa di gestire la modifica e puoi comunque perdere lo stato a causa della ricreazione di Activity da altre modifiche alla configurazione, interruzione del processo o chiusura dell'app. È impossibile disattivare completamente la ricreazione di Activity. Conserva lo stato come descritto in Salva gli stati della UI.
  • Non evitare le modifiche alla configurazione: non applicare limitazioni all'orientamento, alle proporzioni o alla ridimensionabilità per evitare modifiche alla configurazione e la ricreazione di Activity. Ciò influisce negativamente sugli utenti che vogliono utilizzare la tua app nel modo che preferiscono.

Gestisci le modifiche alla configurazione in base alle dimensioni

Le modifiche alla configurazione in base alle dimensioni possono verificarsi in qualsiasi momento e sono più probabili quando l'app viene eseguita su un dispositivo con schermo grande in cui gli utenti possono attivare la modalità multi-finestra. Si aspettano che la tua app funzioni bene in questo ambiente.

Esistono due tipi generali di modifiche alle dimensioni: significative e non significative. Una modifica significativa delle dimensioni è quella in cui un insieme diverso di risorse alternative si applica alla nuova configurazione a causa di una differenza nelle dimensioni dello schermo, ad esempio larghezza, altezza o larghezza minima. Queste risorse includono quelle definite dall'app stessa e quelle di tutte le sue librerie.

Limita la ricreazione delle attività per le modifiche alla configurazione basate sulle dimensioni

Quando disattivi la ricreazione di Activity per le modifiche alla configurazione basate sulle dimensioni, il sistema non ricrea Activity. Riceve invece una chiamata a Activity.onConfigurationChanged. Tutti i componibili che leggono LocalConfiguration.current si ricompongono automaticamente per riflettere le nuove dimensioni.

La ricreazione di Activity è disattivata per le modifiche alla configurazione basate sulle dimensioni quando hai android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" nel file manifest.

Risorse aggiuntive

Per ulteriori informazioni sulla gestione delle modifiche alla configurazione, consulta le seguenti risorse aggiuntive:

Documentazione

Visualizza contenuti