Alcune configurazioni del dispositivo possono cambiare mentre l'app è in esecuzione. Eccone un elenco non esaustivo:
- Dimensioni di visualizzazione dell'app
- Orientamento dello schermo
- Dimensioni e spessore dei caratteri
- 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 modificano lo spazio sullo schermo disponibile per la tua app. Analogamente, la modifica delle impostazioni del dispositivo, come le dimensioni dei caratteri, la lingua o il tema preferito, modifica i rispettivi valori nell'oggetto Configuration
.
Questi parametri in genere richiedono modifiche abbastanza significative all'interfaccia utente dell'applicazione, per cui la piattaforma Android dispone di un meccanismo appositamente progettato per quando cambiano.
Questo meccanismo è una ricreazione di Activity
.
Ricostruzione delle attività
Il sistema ricrea un Activity
quando si verifica una modifica alla configurazione. A tale scopo, il sistema chiama onDestroy()
e distrugge l'istanza Activity
esistente. Quindi viene creata una nuova istanza utilizzando onCreate()
e questa nuova istanza Activity
viene inizializzata con la nuova configurazione aggiornata. Ciò significa anche che il sistema rielabora anche l'interfaccia utente con la nuova configurazione.
Il comportamento di ricreazione aiuta l'applicazione ad adattarsi alle nuove configurazioni ricaricandola automaticamente con risorse alternative corrispondenti alla nuova configurazione del dispositivo.
Esempio di ricreazione
Considera un TextView
che mostra un titolo statico utilizzando
android:text="@string/title"
, come definito in un file XML del layout. Quando viene creata, la vista imposta il testo esattamente una volta, in base alla lingua corrente. Se la lingua cambia, il sistema ricrea l'attività. Di conseguenza, il sistema rielabora anche la vista e la inizializza con il valore corretto in base alla nuova lingua.
La ricreazione cancella anche qualsiasi stato mantenuto come campi in Activity
o in uno dei suoi Fragment
, View
o altri oggetti contenuti. Questo accade perché la ricreazione di Activity
crea un'istanza completamente nuova di Activity
e dell'interfaccia utente. Inoltre, il vecchio Activity
non è più visibile o valido, pertanto eventuali riferimenti rimanenti a questo o agli oggetti in esso contenuti non sono aggiornati. Possono causare bug, perdite di memoria e arresti anomali.
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 di riferimento, l'esperienza utente è negativa se torna a un modulo vuoto o a un altro punto dell'app. In qualità di sviluppatore, devi fornire un'esperienza utente coerente tramite modifiche alla configurazione e ricreazione delle attività.
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 di forma libera
- Chiudere un dispositivo pieghevole con più display
- Modifica del tema di sistema, ad esempio la modalità Buio rispetto alla 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
Esistono tre approcci principali che puoi adottare per preservare lo stato pertinente tramite la Activity
ricostruzione. 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 trattenuti, come le istanze
ViewModel
, per gestire lo stato relativo all'interfaccia utente in memoria mentre l'utente utilizza attivamente l'app. - Stato dell'istanza salvato per gestire l'interruzione del processo avviata dal sistema e mantenere lo stato transitorio che dipende dall'input o dalla navigazione dell'utente.
Per informazioni dettagliate sulle API per ciascuno di questi elementi e su quando è opportuno utilizzarne una, consulta Salvare gli stati dell'interfaccia utente.
Limitare la ricreazione delle attività
Puoi impedire la ricostituzione automatica delle attività per determinate modifiche di configurazione.
La ricreazione di Activity
comporta la ricreazione dell'intera UI e di tutti gli oggetti derivati da Activity
. Potresti avere validi motivi per evitare questa situazione. Ad esempio, l'app potrebbe non dover aggiornare le risorse durante una modifica specifica della configurazione o potresti riscontrare una limitazione del rendimento. In questo caso,
puoi dichiarare che la tua attività gestisce la modifica della configurazione stessa e
impedire al sistema di riavviare l'attività.
Per disattivare la ricostruzione delle attività per determinate modifiche alla configurazione,
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">
Alcune modifiche alla configurazione causano sempre il riavvio dell'attività. Non puoi disattivarli. Ad esempio, non puoi disattivare la modifica dei colori dinamiciintrodotta in Android 12L (livello API 32).
Rispondere alle modifiche alla configurazione nel sistema di visualizzazione
Nel sistema View
, quando si verifica una modifica di configurazione per la quale hai disattivato la ricostituzione di Activity
, l'attività riceve una chiamata a Activity.onConfigurationChanged()
. Anche le visualizzazioni allegate ricevono una chiamata a View.onConfigurationChanged()
. Per le modifiche alla configurazione che non hai aggiunto a android:configChanges
, il sistema ricrea l'attività come di consueto.
Il metodo di callback onConfigurationChanged()
riceve un oggetto
Configuration
che specifica la nuova configurazione del dispositivo. Leggi
i campi dell'oggetto Configuration
per determinare la nuova
configurazione. Per apportare le modifiche successive, aggiorna le risorse
che utilizzi nell'interfaccia. Quando il sistema chiama questo metodo, l'oggetto Resources
della tua attività viene aggiornato in modo da restituire le risorse in base alla nuova configurazione. In questo modo puoi reimpostare gli elementi dell'interfaccia utente senza che il sistema riavvii l'attività.
Ad esempio, la seguente implementazione di onConfigurationChanged()
controlla se è disponibile una tastiera:
Kotlin
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Checks whether a keyboard is available
if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show()
} else if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_NO) {
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show()
}
}
Java
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks whether a keyboard is available
if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show();
} else if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO){
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show();
}
}
Se non devi aggiornare l'applicazione in base a queste modifiche di configurazione, puoi non implementare onConfigurationChanged()
. In questo caso, tutte le risorse utilizzate prima della modifica della configurazione vengono ancora utilizzate e hai evitato solo il riavvio dell'attività. Ad esempio, un'app TV potrebbe non voler reagire quando una tastiera Bluetooth viene collegata o scollegata.
Mantieni stato
Quando utilizzi questa tecnica, devi comunque mantenere lo stato durante il normale ciclo di vita dell'attività. Questo accade per i seguenti motivi:
- Modifiche inevitabili:le modifiche alla configurazione che non puoi impedire possono riavviare l'applicazione.
- Interruzione del processo:l'applicazione deve essere in grado di gestire l'interruzione del processo avviata dal sistema. Se l'utente esce dalla tua applicazione e l'app passa in background, il sistema potrebbe distruggerla.
Rispondere alle modifiche alla configurazione in Jetpack Compose
Jetpack Compose consente alla tua app di reagire più facilmente alle modifiche di configurazione.
Tuttavia, se disattivi la ricostituzione di Activity
per tutte le modifiche alla configurazione ove possibile, 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 LocalConfiguration
locale. Ogni volta che cambia,
le funzioni componibili che leggono da LocalConfiguration.current
si ricompono. Per informazioni sul funzionamento dei valori locali di composizione, 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 di 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 la lingua cambia, l'Activity
che ospita il codice 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 apporti 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, la lingua o il tema di sistema.
- Modifiche alla configurazione: le configurazioni cambiano in base all'interazione dell'utente. Ad esempio, l'utente potrebbe modificare le impostazioni del dispositivo o la modalità di interazione fisica con il dispositivo. Non è possibile impedire le modifiche alla configurazione.
- Rigenerazione
Activity
: per impostazione predefinita, le modifiche alla configurazione comportano la rigenerazione diActivity
. Si tratta di un meccanismo integrato per reinizializzare lo stato dell'app per la nuova configurazione. Activity
destruction: la ricreazione diActivity
fa sì che il sistema elimini l'istanzaActivity
precedente e ne crei una nuova al suo posto. L'istanza precedente è ormai obsoleta. Eventuali riferimenti rimanenti a questo tipo di oggetti possono causare perdite di memoria, bug o arresti anomali.- Stato: lo stato nell'istanza
Activity
precedente non è presente nell'istanzaActivity
nuova, perché si tratta di due istanze di oggetti diverse. Mantieni lo stato dell'app e dell'utente come descritto in Salvare gli stati dell'interfaccia utente. - Disattivazione:la disattivazione della ricostruzione delle attività per un tipo di modifica della configurazione è una potenziale ottimizzazione. Richiede che l'app si aggiorni correttamente in base alla nuova configurazione.
Per offrire un'esperienza utente positiva, segui le best practice riportate di seguito:
- 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 UI. Quando un utente provoca una modifica alla configurazione, si aspetta che le app si aggiornino e continuino a funzionare correttamente con la nuova configurazione.
- Mantieni stato:non perdere lo stato dell'utente quando avviene la
Activity
ricreazione. Conserva lo stato come descritto in Salvare gli stati dell'interfaccia utente. - Evita di disattivare la funzionalità come soluzione rapida:non disattivare la
Activity
ricreazione come scorciatoia per evitare la perdita dello stato. La disattivazione della ricostituzione delle attività richiede di rispettare la promessa di gestire la modifica e puoi comunque perdere lo stato a causa della ricostituzione diActivity
da altre modifiche di configurazione, dall'interruzione del processo o dalla chiusura dell'app. È impossibile disattivare completamente la ricostituzione diActivity
. Conserva lo stato come descritto in Salvare gli stati dell'interfaccia utente. - Non evitare modifiche alla configurazione: non applicare limitazioni all'orientamento, alle proporzioni o alla modifica delle dimensioni 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.
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 questo ambiente.
Esistono due tipi generali di variazioni di dimensioni: significative e insignificanti. Una modifica delle 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 qualsiasi libreria.
Limitare la ricreazione delle attività 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 la ricrea.Activity
Riceve invece una chiamata al numero Activity.onConfigurationChanged()
. Tutte le visualizzazioni allegate ricevono una chiamata al numero
View.onConfigurationChanged()
.
La ricreazione di Activity
è disabilitata per le modifiche alla configurazione in base alle dimensioni se nel file manifest è presente android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout"
.
Consenti la ricreazione delle attività per le modifiche alla configurazione in base alle dimensioni
Su Android 7.0 (livello API 24) e versioni successive, la Activity
ricreazione avviene solo per le modifiche alla configurazione basate sulle dimensioni se la modifica delle dimensioni è significativa. Quando il sistema non rielabora un Activity
a causa di dimensioni insufficienti, potrebbe chiamare Activity.onConfigurationChanged()
e View.onConfigurationChanged()
.
Esistono alcune limitazioni da osservare in merito ai callback Activity
e View
quando Activity
non viene ricreato:
- Su Android 11 (livello API 30) e versioni successive fino ad Android 13 (livello API 33),
Activity.onConfigurationChanged()
non viene chiamato. - Esiste un problema noto per cui
View.onConfigurationChanged()
potrebbe non essere chiamato in alcuni casi su Android 12L (livello API 32) e sulle prime versioni di Android 13 (livello API 33). Per ulteriori informazioni, consulta questo problema pubblico. Il problema è stato risolto nelle release successive di Android 13 e Android 14.
Per il codice che dipende dall'ascolto di modifiche alla configurazione in base alle dimensioni, consigliamo di utilizzare un'utilità View
con un valore View.onConfigurationChanged()
sostituito anziché fare affidamento sulla ricreazione di Activity
o su Activity.onConfigurationChanged()
.