Algumas configurações de dispositivo podem mudar durante a execução, como a orientação da tela, a disponibilidade
do teclado e a ativação do
modo de várias janelas. Quando isso acontece, o Android reinicia a
Activity
em execução (onDestroy()
é chamado, seguido por
onCreate()
). O comportamento de reinicialização foi criado para ajudar
o aplicativo a se adaptar a novas configurações, recarregando-o automaticamente com
recursos alternativos que correspondam à configuração do novo dispositivo.
Para gerenciar corretamente uma reinicialização, é importante que sua atividade restaure o
estado anterior. Você pode usar uma combinação de objetos
onSaveInstanceState()
,
ViewModel
e o armazenamento persistente para salvar e
restaurar o estado da IU da sua atividade durante as mudanças de configuração. Para saber mais sobre como
salvar o estado da sua atividade, leia Como salvar estados da IU.
Para testar se o aplicativo reinicia com o estado intacto, invoque as mudanças de configuração (como a orientação da tela) enquanto executa mais tarefas. O aplicativo precisa ser capaz de reiniciar a qualquer momento sem perda de dados ou estados do usuário para processar eventos como mudanças de configuração ou quando o usuário recebe uma chamada telefônica e retorna depois da exclusão do processo. Para conferir como restaurar o estado da atividade, leia sobre o Ciclo de vida da atividade.
No entanto, talvez você se depare com uma situação em que o reinício do aplicativo e a restauração representem quantidades significativas de dados que podem ser custosos e prejudicar a experiência do usuário. Nessa situação, há duas opções:
- Reter um objeto durante uma mudança de configuração
Permita que a atividade reinicie quando uma configuração mudar, mas transporte um objeto com estado para a nova instância da atividade.
- Processar a mudança de configuração por conta própria
Não é recomendado manipular as mudanças de configuração devido à complexidade desse processo. No entanto, se você não conseguir preservar o estado da IU usando as opções preferidas (objetos
onSaveInstanceState()
,ViewModel
e armazenamento permanente), é possível impedir que o sistema a reinicie durante determinadas mudanças de configuração. Seu app vai receber um callback quando as configurações mudarem para que você possa atualizar manualmente sua atividade conforme necessário.
Reter um objeto durante uma mudança de configuração
Se a retenção da atividade exigir que você extraia grandes conjuntos de dados, restabeleça uma conexão
de rede ou execute outras operações intensivas, um reinício completo devido a uma mudança
de configuração pode prejudicar a experiência do usuário. Além disso, pode não ser possível restaurar completamente o
estado da atividade com o Bundle
que o sistema salva com o callback
onSaveInstanceState()
. Ele não foi
criado para transportar objetos grandes (como bitmaps), e os dados contidos nele precisam ser serializados e
desserializados na linha de execução principal, o que pode consumir muita memória e retardar a
mudança de configuração. Nessa
situação, você pode aliviar o peso de reinicializar parte da sua atividade usando um
ViewModel
. Os objetos ViewModel
são
preservados em todas as mudanças de configuração. Por isso, eles são o local perfeito para manter seus dados de IU sem precisar consultá-los
novamente. Para saber mais sobre o uso da classe ViewModel
nos seus apps, leia a
Visão geral do ViewModel.
Processar a mudança de configuração por conta própria
Se o aplicativo não tiver que atualizar recursos durante uma mudança de configuração específica e se houver alguma limitação de performance que impeça a atividade de reiniciar, vai ser possível declarar que a atividade processa a mudança de configuração, o que vai evitar que o sistema reinicie a atividade.
Cuidado: processar a mudança de configuração por conta própria pode dificultar muito o uso de recursos alternativos, já que o sistema não os aplicará automaticamente. Essa técnica precisa ser considerada um último recurso, quando é preciso evitar reinícios devido a uma mudança de configuração, e não é recomendada para a maioria dos aplicativos.
Para declarar que a atividade processa uma mudança de configuração, edite o elemento <activity>
apropriado no
arquivo de manifesto para que inclua o atributo android:configChanges
com um valor que represente a configuração a ser
processada. Os valores possíveis estão listados na documentação do atributo
android:configChanges
. Os valores mais comuns são "orientation"
, "screenSize"
"screenLayout"
e "keyboardHidden"
.
- O valor
"orientation"
evita reinicializações quando a orientação da tela é modificada. - O valor
"screenSize"
também impede reinicializações quando a orientação muda, mas apenas para o Android 3.2 (nível 13 da API) e versões mais recentes. - O valor
"screenLayout"
é necessário para detectar mudanças que possam ser acionadas por dispositivos como smartphones dobráveis e Chromebooks conversíveis. - O valor
"keyboardHidden"
impede a reinicialização quando a disponibilidade do teclado é modificada.
Se você quiser processar as mudanças de configuração manualmente no app, declare os
valores "orientation"
, "screenSize"
e "screenLayout"
nos
atributos android:configChanges
. Para declarar vários valores de configuração
no atributo, use um separador, como o caractere de barra reta |
.
Por exemplo, o código de manifesto abaixo declara uma atividade que processa tanto a mudança de orientação da tela quanto a disponibilidade do teclado:
<activity android:name=".MyActivity" android:configChanges="orientation|screenSize|screenLayout|keyboardHidden" android:label="@string/app_name">
Agora, quando ocorre uma mudança em uma dessas configurações, o MyActivity
não é reiniciado.
Em vez disso, MyActivity
recebe uma chamada para
onConfigurationChanged()
.
O método onConfigurationChanged()
é transmitido ao objeto Configuration
, que especifica
a nova configuração do dispositivo. Ao ler os campos no objeto Configuration
,
é possível determinar a nova configuração e atualizar os recursos na interface
para fazer as mudanças adequadas. No momento
em que o método é chamado, o objeto Resources
da atividade é atualizado
para retornar recursos com base na nova configuração, o que facilita
a redefinição de elementos da IU sem que o sistema reinicie a atividade.
Por exemplo, a implementação de onConfigurationChanged()
abaixo verifica a orientação atual do dispositivo:
Kotlin
override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) // Checks the orientation of the screen if (newConfig.orientation === Configuration.ORIENTATION_LANDSCAPE) { Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show() } else if (newConfig.orientation === Configuration.ORIENTATION_PORTRAIT) { Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show() } }
Java
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Checks the orientation of the screen if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show(); } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){ Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show(); } }
O objeto Configuration
representa todas as configurações atuais,
não somente as que mudaram. Na maior parte do tempo, não importa como
a configuração foi modificada. Basta reatribuir todos os recursos que apresentam alternativas
à configuração que está sendo processada. Por exemplo, como o objeto
Resources
está atualizado, você pode redefinir
qualquer instância ImageView
com
setImageResource()
e o recurso adequado para a nova configuração vai ser usado (como descrito na Visão geral de recursos de app).
Os valores dos campos de Configuration
são números inteiros
que correspondem a constantes específicas da classe Configuration
. Para conferir a documentação sobre as
constantes que for usar em cada campo, consulte o campo em questão na referência sobre
Configuration
.
Não esqueça: ao declarar a atividade para processar uma mudança de configuração,
você é responsável por redefinir todos os elementos que fornecem alternativas. Se você
declarar a atividade para processar a mudança de orientação e tiver imagens que mudariam
entre as orientações de paisagem e retrato, vai ser necessário reatribuir cada recurso a cada elemento durante
onConfigurationChanged()
.
Se não for necessário atualizar o aplicativo com base nessas mudanças
de configuração, não implemente onConfigurationChanged()
. Nesse
caso, todos os recursos usados antes da mudança de configuração ainda são usados,
e somente o reinício da atividade é evitado.
No entanto, não considere essa técnica como um fuga da retenção de estado durante o ciclo de vida normal da atividade. O aplicativo precisa sempre conseguir ser desligado e reiniciado com o estado anterior intacto. Mudanças de configuração que não podem ser impedidas podem reiniciar o aplicativo. Se o usuário sair do aplicativo e o app for colocado em segundo plano, o sistema vai poder destruir o aplicativo.