Gestire le modifiche alla configurazione

Alcune configurazioni del dispositivo possono cambiare durante l'esecuzione dell'app. Questi 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, cambia i rispettivi valori nell'oggetto Configuration.

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

Ricreazione dell'attività

Il sistema ricrea un Activity quando si verifica una modifica alla configurazione. Per farlo, il sistema chiama onDestroy e distrugge 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 l'interfaccia utente con la nuova configurazione.

In genere, Activity funge da host per i composable. Quando Activity viene ricreato, Compose ricrea anche la tua 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 attività ricreativa

Considera un composable 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, il componente componibile Text legge la configurazione attuale (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 la configurazione attuale, il titolo viene aggiornato automaticamente con il valore localizzato corretto.

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

Per preservare lo stato dell'interfaccia utente in seguito alle 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 si aggiorna per riflettere la nuova configurazione.

Per saperne di più sul salvataggio dello stato in Compose, consulta Salvare lo stato della UI 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 informazioni, l'esperienza utente è negativa se torna a un modulo cancellato o in un altro punto dell'app. In qualità di sviluppatore, devi fornire un'esperienza utente coerente tramite modifiche alla configurazione e ricreazione dell'attività.

Per verificare se lo stato viene mantenuto nell'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
  • Ridimensionamento dell'applicazione in modalità multi-finestra o in una finestra in formato libero
  • Chiusura di un dispositivo pieghevole con più display
  • Modifica del tema di sistema, ad esempio modalità Buio e modalità Luce
  • Modificare le dimensioni del carattere
  • Modificare la lingua di sistema o dell'app
  • Collegare o scollegare una tastiera hardware
  • Collegamento o scollegamento di una base di ricarica

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. L'archiviazione locale persistente include database o DataStore.
  • Oggetti conservati, ad esempio istanze ViewModel per gestire lo stato relativo all'interfaccia utente in memoria mentre l'utente utilizza attivamente l'app.
  • rememberSaveable per preservare lo stato transitorio dell'interfaccia utente tra 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 elementi e su quando è opportuno utilizzarli, consulta Salvataggio degli stati della UI.

Limitare la ricreazione dell'attività

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

Per impostazione predefinita, una modifica alla configurazione costringe il sistema a eliminare e ricreare l'attività, inclusa la UI e qualsiasi oggetto derivato dall'attività. Se dichiari che la tua attività gestisce la modifica alla configurazione, il sistema lo impedisce. Invece, 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:

  • Rendimento migliorato:la ricomposizione della UI è meno costosa di un ciclo completo di ricreazione dell'attività, soprattutto per modifiche minori.
  • Animazioni fluide:se eviti il riavvio di un'attività, puoi eseguire animazioni continue durante le modifiche alla configurazione, ad esempio transizioni di layout fluide durante la rotazione del dispositivo.
  • Conservazione dello stato:il mantenimento dell'istanza dell'attività riduce il rischio di perdita temporanea dello stato dell'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 particolari 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 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 alla tua 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, la tua app deve comunque gestire correttamente le modifiche alla configurazione.

L'oggetto Configuration è disponibile nella gerarchia dell'interfaccia utente di Compose con la composizione locale LocalConfiguration. Ogni volta che cambia, le funzioni componibili che leggono da LocalConfiguration.current vengono ricomposte. Per informazioni su come funzionano i CompositionLocal, vedi Dati con ambito locale con CompositionLocal.

Esempio

Nell'esempio seguente, un elemento componibile 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'hosting di Activity il codice Compose deve disattivare le modifiche alla configurazione della lingua. 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 alle modifiche alla configurazione:

  • Configurazioni:le configurazioni del dispositivo definiscono la modalità di visualizzazione dell'interfaccia utente per l'utente, ad esempio le dimensioni di visualizzazione dell'app, le impostazioni locali 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 Activity: le modifiche alla configurazione comportano la ricreazione 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 elimini la vecchia istanza di Activity e ne crei una nuova al suo posto. La vecchia istanza è ora obsoleta. Evita di conservare riferimenti a oggetti con ambito del ciclo di vita oltre il loro 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é collegare lo stato all'attività, utilizza le API consigliate per preservare lo stato dell'app e dell'utente, come descritto in Salvare gli stati dell'interfaccia utente.
  • Disattivazione:la disattivazione della ricreazione dell'attività per un tipo di modifica della configurazione richiede che l'app si aggiorni correttamente in risposta alla nuova configurazione.

Per garantire una buona esperienza utente, segui le best practice riportate di seguito:

  • Preparati a modifiche frequenti della 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 UI. Quando un utente causa una modifica alla configurazione, si aspetta che le app si aggiornino e continuino a funzionare correttamente con la nuova configurazione.
  • Preserve state:non perdere lo stato dell'utente quando si verifica la ricreazione di Activity. Conserva lo stato come descritto in Salvare gli stati dell'interfaccia utente utilizzando API come ViewModel e rememberSaveable.
  • Evita di disattivare la ricreazione 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 rispettare la promessa di gestire la modifica e potresti comunque perdere lo stato a causa della ricreazione di Activity dovuta ad altre modifiche alla configurazione, all'interruzione del processo o alla chiusura dell'app. È impossibile disattivare completamente la ricreazione di Activity. Conserva lo stato come descritto in Salvare gli stati dell'interfaccia utente.
  • Non evitare modifiche alla configurazione:non imporre restrizioni a orientamento, proporzioni o ridimensionamento per evitare modifiche alla configurazione e ricreazione di Activity. 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 la tua app funzioni bene in quell'ambiente.

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

Limita la ricreazione dell'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. Qualsiasi composable che legge LocalConfiguration.current viene ricomposto 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