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 ha un meccanismo appositamente creato per quando cambiano.
Questo meccanismo è una Activity ricreazione.
Attività ricreative
Il sistema ricrea un Activity quando si verifica una modifica alla configurazione. A questo scopo, 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 anche la UI con la nuova 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 TextView che mostra un titolo statico utilizzando
android:text="@string/title", come definito in un file XML di layout. Quando viene creata la visualizzazione, il testo viene impostato esattamente una volta, in base alla lingua corrente. Se la lingua cambia, il sistema ricrea l'attività. Di conseguenza, il sistema
ricrea anche la visualizzazione 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 qualsiasi dei suoi oggetti Fragment, View o altri oggetti contenuti. Questo
perché la ricreazione di Activity crea un'istanza completamente nuova di Activity
e della UI. Inoltre, il vecchio Activity non è più visibile o valido, quindi tutti i
riferimenti rimanenti a esso o ai suoi oggetti contenuti non sono più 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 informazioni, è una cattiva esperienza utente se torna a un modulo cancellato o in un'altra parte 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
- Piegare 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
- Collegare o scollegare una base di ricarica
Esistono tre approcci principali 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. - Stato dell'istanza salvato per gestire l'interruzione del processo avviata dal sistema e mantenere lo stato temporaneo che dipende dall'input utente o dalla navigazione.
Per leggere informazioni dettagliate sulle API per ciascuno di questi elementi e 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.
La ricreazione di Activity comporta la ricreazione dell'intera UI e di tutti gli oggetti derivati
da Activity. Potresti avere validi motivi per evitarlo. Ad esempio, la tua app potrebbe non aver bisogno di aggiornare le risorse durante una specifica modifica della configurazione oppure potresti avere una limitazione delle prestazioni. In questo caso,
puoi dichiarare che la tua attività gestisce la modifica alla configurazione e
impedire al sistema di riavviarla.
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">
Alcune modifiche alla configurazione causano sempre il riavvio dell'attività. Non puoi disattivarli. Ad esempio, non puoi disattivare la modifica dei colori dinamici introdotta in Android 12L (livello API 32).
Reagire alle modifiche alla configurazione nel sistema di visualizzazione
Nel sistema View, quando si verifica una modifica alla configurazione per la quale hai
disattivato la ricreazione 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 nell'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 dell'attività viene aggiornato per restituire le risorse in base alla nuova configurazione. In questo modo puoi reimpostare gli elementi della UI senza che il sistema
riavvii la tua 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
alla configurazione, puoi invece non implementare onConfigurationChanged(). In questo
caso, tutte le risorse utilizzate prima della modifica della configurazione vengono comunque utilizzate
e hai solo evitato il riavvio dell'attività. Ad esempio, un'app TV
potrebbe non voler reagire quando una tastiera Bluetooth viene collegata o scollegata.
Mantieni lo stato
Quando utilizzi questa tecnica, devi comunque mantenere lo stato durante il normale ciclo di vita dell'attività. Ciò è dovuto a quanto segue:
- Modifiche inevitabili:le modifiche alla configurazione che non puoi impedire possono riavviare l'applicazione.
- Interruzione del processo:la tua applicazione deve essere in grado di gestire l'interruzione del processo avviata dal sistema. Se l'utente esce dall'applicazione e l'app passa in background, il sistema potrebbe eliminarla.
Reagire alle modifiche alla configurazione in Jetpack Compose
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'Activity che ospita il
codice di composizione 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 alle modifiche alla configurazione:
- Configurazioni:le configurazioni del dispositivo definiscono la modalità di visualizzazione della UI per l'utente, ad esempio le dimensioni di visualizzazione dell'app, le impostazioni internazionali o il tema di sistema.
- 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 modifiche alla configurazione.
- Ricreazione di
Activity:le modifiche alla configurazione comportano la ricreazione diActivityper impostazione predefinita. Si tratta di un meccanismo integrato per reinizializzare lo stato dell'app per la nuova configurazione. - Distruzione di
Activity:la ricreazione diActivityfa sì che il sistema elimini l'istanzaActivityprecedente e ne crei una nuova al suo posto. La vecchia istanza è ora obsoleta. Qualsiasi riferimento rimanente comporta perdite di memoria, bug o arresti anomali. - Stato:lo stato nella vecchia istanza
Activitynon è presente nella nuova istanzaActivity, perché si tratta di due istanze di oggetti diverse. Conserva lo stato dell'app e dell'utente come descritto in Salva stati UI. - Disattivazione:la disattivazione della ricreazione dell'attività per un tipo di modifica alla configurazione è una potenziale ottimizzazione. 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 della 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. - Evita di disattivare la funzionalità come soluzione rapida:non disattivare la ricreazione di
Activitycome 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 diActivitydovuta ad altre modifiche alla configurazione, all'interruzione del processo o alla chiusura dell'app. È impossibile disattivare completamente la ricreazione diActivity. Conserva lo stato come descritto in Salvare gli stati dell'interfaccia utente. - Non evitare modifiche alla configurazione: non imporre restrizioni su 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 basate sulle 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 significativa delle dimensioni è 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 al numero
Activity.onConfigurationChanged(). Tutte le viste allegate ricevono una chiamata a
View.onConfigurationChanged().
La ricreazione di Activity è disattivata per le modifiche alla configurazione basate sulle dimensioni quando
hai
android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout"
nel file manifest.
Consenti la ricreazione dell'attività per le modifiche alla configurazione basate sulle dimensioni
Su Android 7.0 (livello API 24) e versioni successive, la Activity ricreazione si verifica solo per le modifiche alla configurazione basate sulle dimensioni se la modifica delle dimensioni è significativa. Quando il sistema non
ricrea 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) 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 nelle prime versioni di Android 13 (livello API 33). Per saperne di più, consulta questo problema pubblico. Il problema è stato risolto nelle versioni successive di Android 13 e in Android 14.
Per il codice che dipende dall'ascolto delle modifiche alla configurazione in base alle dimensioni, consigliamo di utilizzare un'utilità View con un View.onConfigurationChanged() sottoposto a override anziché fare affidamento sulla ricreazione di Activity o su Activity.onConfigurationChanged().