Alcune configurazioni del dispositivo possono cambiare mentre l'app è in esecuzione. 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 avviene a causa di alcune interazioni dell'utente. Ad esempio, ruotando o piegando il dispositivo viene modificata la quantità di spazio sullo schermo disponibile per la tua app. Allo stesso modo, l'alterazione delle impostazioni del dispositivo, come le dimensioni del carattere, la lingua o il tema preferito, comporta la modifica dei rispettivi valori nell'oggetto Configuration
.
Questi parametri di solito richiedono modifiche abbastanza significative all'interfaccia utente dell'applicazione da far sì che la piattaforma Android disponga di un meccanismo creato appositamente in caso di modifica.
Questo meccanismo è ricreazione di Activity
.
Attività ricreative
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 anche la UI con la nuova configurazione.
Il comportamento della nuova creazione consente all'applicazione di adattarsi alle nuove configurazioni ricaricando automaticamente l'applicazione con risorse alternative che corrispondono alla nuova configurazione del dispositivo.
Esempio per attività ricreative
Considera un TextView
che mostra un titolo statico utilizzando android:text="@string/title"
, come definito in un file XML di layout. Una volta creata, la visualizzazione
imposta il testo esattamente una volta, in base alla lingua corrente. Se la lingua cambia, il sistema ricrea l'attività. Di conseguenza, anche il sistema ricrea la vista e la inizializza al valore corretto in base alla nuova lingua.
La ricreazione cancella anche tutti gli stati conservati come campi in Activity
o nei 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 valore precedente di Activity
non è più visibile o valido, pertanto eventuali
riferimenti rimanenti al file o agli oggetti contenuti sono obsoleti. 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 compila un modulo e apre un'altra app in modalità multi-finestra per fare riferimento alle informazioni, l'esperienza utente è negativa se torna a un modulo cancellato o si trova in un'altra posizione dell'app completamente diversa. 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 nell'applicazione, puoi eseguire azioni che causano modifiche alla configurazione sia quando l'app è in primo piano che mentre è 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
- Come piegare un dispositivo pieghevole con più display
- Modifica del tema del sistema, ad esempio modalità Buio rispetto a modalità Luce
- Modifica delle dimensioni dei caratteri
- Modifica della 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
attraverso la ricreazione di Activity
. L'utilizzo dipende dal tipo di stato che vuoi conservare:
- Persistenza locale per gestire la morte del processo per dati complessi o di grandi dimensioni.
L'archiviazione locale permanente include database o
DataStore
. - Oggetti conservati, ad esempio istanze di
ViewModel
, per gestire lo stato relativo all'interfaccia utente in memoria mentre l'utente utilizza attivamente l'app. - Stato dell'istanza salvata per gestire l'interruzione del processo avviato dal sistema e mantenere lo stato temporaneo che dipende dall'input o dalla navigazione dell'utente.
Per informazioni dettagliate sulle API per ciascuna di queste opzioni e sul loro utilizzo, consulta Salvare gli stati della UI.
Limita attività ricreative
Puoi impedire la ricreazione automatica delle attività per determinate modifiche alla configurazione.
La ricreazione di Activity
comporta la creazione dell'intera UI e di tutti gli oggetti derivati
da Activity
. Potresti avere buoni motivi per evitare questa situazione. Ad esempio,
l'app potrebbe non aver bisogno di aggiornare le risorse durante una modifica
specifica 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 delle 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 per l'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">
Alcune modifiche alla configurazione comportano sempre il riavvio dell'attività. Non puoi disabilitarle. Ad esempio, non puoi disabilitare la modifica dinamica dei colori introdotta in Android 12L (livello API 32).
Reagisci alle modifiche alla configurazione nel sistema di visualizzazione
Nel sistema View
, quando si verifica una modifica alla configurazione per cui hai disattivato la ricreazione di Activity
, l'attività riceve una chiamata a Activity.onConfigurationChanged()
. Anche tutte le viste allegate ricevono una
chiamata a View.onConfigurationChanged()
. Per le modifiche alla configurazione
non aggiunte 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
dell'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()
verifica
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 scegliere di non implementare onConfigurationChanged()
. In questo caso, tutte le risorse utilizzate prima della modifica alla configurazione saranno ancora utilizzate, evitando solo il riavvio dell'attività. Ad esempio, un'app TV potrebbe non voler reagire quando una tastiera Bluetooth viene collegata o scollegata.
Conserva stato
Quando utilizzi questa tecnica, devi mantenere lo stato durante il normale ciclo di vita dell'attività. Ciò è dovuto ai seguenti motivi:
- Modifiche non evitabili: le modifiche alla configurazione che non puoi impedire possono riavviare l'applicazione.
- Morte di un processo: la tua applicazione deve essere in grado di gestire la morte di un processo avviata dal sistema. Se l'utente abbandona l'applicazione e questa passa in background, il sistema potrebbe eliminarla.
Reagisci alle modifiche alla configurazione in Jetpack Compose
Jetpack Compose consente alla tua app di reagire più facilmente alle modifiche alla configurazione.
Tuttavia, se disabiliti la ricreazione di Activity
per tutte le modifiche alla configurazione
dove è possibile, l'app deve comunque gestire correttamente
le modifiche.
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
si ricompongono. Per
informazioni su come funziona la composizione locale, consulta Dati con ambito locale
con ComposeLocal.
Esempio
Nell'esempio seguente, un componibile visualizza una data con un formato specifico.
Il componibile reagisce alle modifiche della 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 cambiano le impostazioni internazionali, Activity
che ospita il codice di composizione deve disattivare le modifiche alla configurazione delle impostazioni internazionali. Per farlo, imposta android:configChanges
su locale|layoutDirection
.
Modifiche alla configurazione: concetti chiave e best practice
Di seguito sono riportati i concetti chiave che devi conoscere quando apporti modifiche alla configurazione:
- Configurazioni: le configurazioni del dispositivo definiscono il modo in cui l'UI viene visualizzata dall'utente, ad esempio dimensioni di visualizzazione dell'app, impostazioni internazionali o tema di sistema.
- Modifiche alla configurazione:le configurazioni cambiano attraverso 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 c'è modo di impedire le modifiche alla configurazione.
- Ricreazione di
Activity
: le modifiche alla configurazione comportano la ricreazione diActivity
per impostazione predefinita. Si tratta di un meccanismo integrato per reinizializzare lo stato dell'app per la nuova configurazione. - Eliminazione di
Activity
: la ricreazioneActivity
fa sì che il sistema elimini la precedente istanzaActivity
e ne crei una nuova in sostituzione. La vecchia istanza ora è obsoleta. Eventuali riferimenti rimanenti causano perdite di memoria, bug o arresti anomali. - Stato: lo stato della vecchia istanza
Activity
non è presente nella nuova istanzaActivity
perché si tratta di due istanze di oggetto diverse. Mantiene lo stato dell'app e dell'utente come descritto in Salvare gli stati dell'UI. - Disattivazione: la disattivazione della ricreazione delle attività per un tipo di modifica della configurazione è una potenziale ottimizzazione. Richiede che l'app venga aggiornata correttamente in risposta alla nuova configurazione.
Per offrire una buona esperienza utente, osserva le seguenti best practice:
- Preparati a modifiche frequenti alla configurazione: non dare per scontato che le modifiche alla configurazione siano rare o mai eseguite, indipendentemente dal livello API, dal fattore di forma o dal toolkit dell'interfaccia utente. Quando un utente provoca una modifica alla configurazione, si aspetta che le app vengano aggiornate e che continuino a funzionare correttamente con la nuova configurazione.
- Conserva lo stato: non viene perso lo stato dell'utente quando viene eseguita la ricreazione
Activity
. Conserva lo stato come descritto in Salvare gli stati della UI. - Evita la disattivazione come soluzione rapida: non disattivare la ricreazione di
Activity
come scorciatoia per evitare la perdita di stato. Per disattivare la ricreazione dell'attività, devi mantenere la promessa di gestire il cambiamento e puoi comunque perdere lo stato a causa della ricreazione diActivity
da altre modifiche della configurazione, della morte di un processo o della chiusura dell'app. È impossibile disattivare completamente la riproduzione diActivity
. Conserva lo stato come descritto in Salvare gli stati della UI. - Non evitare modifiche alla configurazione: non applicare limitazioni su orientamento,
proporzioni o ridimensionabilità per evitare modifiche alla configurazione e
Activity
ricreazione. Questo ha un impatto negativo 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 basata sulle dimensioni possono essere apportate 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 quell'ambiente.
Esistono due tipi generali di modifiche delle dimensioni: significative e non significative. Un cambiamento significativo delle dimensioni si verifica quando alla nuova configurazione viene applicato un insieme diverso di risorse alternative a causa di una differenza nelle dimensioni dello schermo, ad esempio larghezza, altezza o larghezza inferiore. Queste risorse includono quelle definite dall'app e quelle provenienti da una qualsiasi delle sue librerie.
Limita la ricreazione delle attività per le modifiche alla configurazione in base alle dimensioni
Quando disabiliti la ricreazione di Activity
per le modifiche alla configurazione basata 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
è disabilitata per le modifiche alla configurazione in base alle dimensioni se
nel file manifest è presente
android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout
".
Consenti la ricreazione dell'attività per le modifiche alla configurazione in base alle dimensioni
Su Android 7.0 (livello API 24) e versioni successive, se la modifica delle dimensioni è significativa, viene eseguita solo la ricreazione di Activity
per le modifiche della configurazione basata sulle dimensioni. Quando il sistema non
ricrea un elemento Activity
a causa di dimensioni insufficienti, potrebbe invece chiamare
Activity.onConfigurationChanged()
e
View.onConfigurationChanged()
.
È necessario osservare alcune avvertenze in merito ai callback Activity
e View
quando Activity
non viene ricreato:
- Da Android 11 (livello API 30) ad Android 13 (livello API 33),
Activity.onConfigurationChanged()
non viene chiamato. - Esiste un problema noto per cui in alcuni casi
View.onConfigurationChanged()
potrebbe non essere chiamato su Android 12L (livello API 32) e nelle prime versioni di Android 13 (livello API 33). Per ulteriori informazioni, consulta questo problema pubblico. Questo problema è stato risolto nelle versioni successive di Android 13 e Android 14.
Per il codice che dipende dall'ascolto di modifiche alla configurazione basate sulle dimensioni, ti consigliamo di utilizzare un'utilità View
con View.onConfigurationChanged()
con override, anziché utilizzare Activity
ricreazione o Activity.onConfigurationChanged()
.