Gestire le modifiche alla configurazione

Alcune configurazioni dei dispositivi possono cambiare mentre l'app è in esecuzione. Queste includono, a titolo esemplificativo:

  • Dimensioni di visualizzazione dell'app
  • Orientamento schermo
  • Dimensioni e spessore del carattere
  • Impostazioni internazionali
  • Modalità Buio e modalità Luce
  • 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 chiusura del dispositivo modifica la quantità di spazio sullo schermo disponibile per l'app. Allo stesso modo, la modifica delle impostazioni del dispositivo, come le dimensioni del carattere, la lingua o il tema preferito, modifica i rispettivi valori nell'Configuration oggetto.

Questi parametri in genere richiedono modifiche sufficientemente grandi all'interfaccia utente dell'applicazione, tanto che la piattaforma Android ha un meccanismo appositamente creato per quando cambiano. Questo meccanismo è la ricreazione di Activity.

Ricreazione di Activity

Il sistema ricrea un'istanza di Activity quando si verifica una modifica alla configurazione. A questo scopo, il sistema chiama onDestroy ed elimina l'istanza Activityesistente. Poi crea una nuova istanza utilizzando onCreate, che viene inizializzata con la nuova Activity configurazione aggiornata. Ciò significa anche che il sistema ricrea l'interfaccia utente con la nuova configurazione.

In genere, Activity funge da host per i composable. Quando Activity viene ricreata, Compose ricrea anche l'interfaccia utente utilizzando i nuovi valori di configurazione.

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

Esempio di ricreazione

Considera un composable che visualizza 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 creata Activity, il composable 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 l'interfaccia utente. Poiché stringResource legge dalla configurazione corrente, il titolo viene aggiornato automaticamente al valore localizzato corretto.

La ricreazione cancella anche qualsiasi stato mantenuto come campi in Activity.

Per mantenere lo stato dell'interfaccia utente 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 l'interfaccia utente viene aggiornata per riflettere la nuova configurazione.

Per saperne di più sul salvataggio dello stato in Compose, consulta Salvare lo stato dell'interfaccia utente in Compose.

Aspettative degli utenti

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

Per verificare se lo stato viene mantenuto 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:

  • Ruotare il dispositivo
  • Attivare la modalità multi-finestra
  • Ridimensionare l'applicazione in modalità multi-finestra o in una finestra in formato libero
  • Chiudere un dispositivo pieghevole con più display
  • Modificare il tema del sistema, ad esempio la modalità Buio e la modalità Luce
  • Modificare le dimensioni del carattere
  • Modificare la lingua del sistema o dell'app
  • Collegare o scollegare una tastiera hardware
  • Collegare o scollegare una docking station

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

  • 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 mantenuti, come le istanze di ViewModel, per gestire lo stato relativo all'interfaccia utente in memoria mentre l'utente utilizza attivamente l'app.
  • rememberSaveable per mantenere lo stato dell'interfaccia utente temporaneo durante le modifiche alla configurazione e l'interruzione del processo avviata dal sistema. Questa opzione è appropriata per lo stato che dipende dall'input dell'utente, dalla posizione di scorrimento o dalla navigazione, ma non appartiene a ViewModel.

Per leggere informazioni dettagliate sulle API per ciascuna di queste opzioni, e quando è appropriato utilizzarle, consulta Salvare gli stati dell'interfaccia utente.

Limitare la ricreazione di Activity

Puoi impedire la ricreazione automatica di Activity per determinate modifiche alla configurazione. Nelle moderne app solo Compose, l'interfaccia utente viene ricomposta in entrambi i casi, ma è consigliabile gestire direttamente la modifica alla configurazione.

Per impostazione predefinita, una modifica alla configurazione costringe il sistema a eliminare 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 alla configurazione, il sistema impedisce questa operazione. Invece, viene aggiornato solo l'oggetto Configuration e Compose ricompone l'interfaccia utente con i nuovi valori.

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

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

Per disattivare la ricreazione di Activity per modifiche alla configurazione specifiche, aggiungi il tipo di configurazione a android:configChanges nella voce <activity> del file AndroidManifest.xml. I valori possibili sono riportati nella documentazione dell'attributo android:configChanges.

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

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

Reagire alle modifiche alla configurazione

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

L'Configuration oggetto è disponibile nella gerarchia dell'interfaccia utente di Compose con la composizione locale LocalConfiguration. Ogni volta che cambia, le funzioni composable che leggono da LocalConfiguration.current vengono ricomposte. Per informazioni sul funzionamento delle composizioni locali, consulta Dati con ambito locale con CompositionLocal.

Esempio

Nell'esempio seguente, un composable visualizza 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 cambiano le impostazioni internazionali, Activity che ospita il codice Compose deve disattivare le modifiche alla configurazione delle impostazioni internazionali. A questo scopo, 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 dei dispositivi definiscono la modalità di visualizzazione dell'interfaccia utente per l'utente, ad esempio le dimensioni di visualizzazione dell'app, le impostazioni internazionali o il tema del 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: per impostazione predefinita, le modifiche alla configurazione comportano la ricreazione di Activity. Si tratta di un meccanismo integrato per reinizializzare lo stato dell'app per la nuova configurazione.
  • Eliminazione di Activity: la ricreazione di Activity fa sì che il sistema elimini la vecchia istanza di Activity 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 di Activity non è presente nella nuova istanza di Activity, perché si tratta di due istanze di oggetti diversi. Anziché associare lo stato all'attività, utilizza le API consigliate per mantenere lo stato dell'app e dell'utente come descritto in Salvare gli stati dell'interfaccia utente.
  • Disattivazione: la disattivazione della ricreazione di Activity per un tipo di modifica alla configurazione richiede che l'app venga aggiornata correttamente in risposta alla nuova configurazione. Per la maggior parte delle app Compose, questa operazione non è consigliata.

Per offrire una buona esperienza utente, segui le seguenti best practice:

  • Preparati a modifiche frequenti 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 causa una modifica alla configurazione, si aspetta che le app vengano aggiornate e continuino a funzionare correttamente con la nuova configurazione.
  • Mantieni lo stato: non perdere lo stato dell'utente quando si verifica la ricreazione di Activity. Mantieni lo stato come descritto in Salvare gli stati dell'interfaccia utente utilizzando API come ViewModel e rememberSaveable.
  • Evita di disattivare la ricreazione di Activity come soluzione rapida: non disattivare la ricreazione di Activity come scorciatoia per evitare la perdita di stato. La disattivazione della ricreazione di Activity richiede di rispettare la promessa di gestire la modifica e puoi comunque perdere lo stato a causa della ricreazione di Activity da altre modifiche alla configurazione, dalla chiusura del processo o dalla chiusura dell'app. È impossibile disattivare completamente la ricreazione di Activity. Mantieni lo stato come descritto in Salvare gli stati dell'interfaccia utente.
  • Non evitare le modifiche alla configurazione: non imporre limitazioni all'orientamento, alle proporzioni o alla ridimensionabilità per evitare modifiche alla configurazione e Activity ricreazione. Ciò influisce negativamente sugli utenti che vogliono utilizzare la tua app nel modo che preferiscono.

Gestire 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 di grandi dimensioni in cui gli utenti possono attivare la modalità multi-finestra. Si aspettano che l'app funzioni bene in questo ambiente.

Esistono due tipi generali di modifiche alle dimensioni: significative e non significative. Una modifica alle dimensioni significativa è 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 una delle sue librerie.

Limitare la ricreazione di Activity per le modifiche alla configurazione in base alle dimensioni

Quando disattivi la ricreazione di Activity per le modifiche alla configurazione in base alle dimensioni, il sistema non ricrea Activity. Riceve invece una chiamata a Activity.onConfigurationChanged. Tutti i composable che leggono LocalConfiguration.current vengono ricomposti automaticamente per riflettere le nuove dimensioni.

La ricreazione di Activity è disattivata per le modifiche alla configurazione in base alle dimensioni quando nel file manifest è presente android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout".

Risorse aggiuntive

Per saperne di più sulla gestione delle modifiche alla configurazione, consulta le seguenti risorse aggiuntive:

Documentazione

Visualizzazioni dei contenuti