1. Antes de começar
Neste codelab, você vai aprender sobre uma parte fundamental do Android: o ciclo de vida da atividade.
Durante o ciclo de vida, uma atividade transita entre diferentes estados e, às vezes, retorna a um deles. Essa transição de estados é conhecida como "ciclo de vida da atividade".
No Android, uma atividade é o ponto de entrada para a interação com o usuário.
Antes, uma atividade mostrava uma tela em um app. Com as práticas recomendadas atuais, uma atividade pode mostrar várias telas e alternar entre elas, conforme necessário.
O ciclo de vida da atividade se estende desde a criação até a destruição da atividade, quando o sistema recupera os recursos dela. À medida que o usuário navega para dentro e para fora de uma atividade, cada atividade transita entre diferentes estados no ciclo de vida.
Como desenvolvedor Android, você precisa compreender o ciclo de vida da atividade. Se as atividades não responderem corretamente às mudanças de estado do ciclo de vida, é possível que o app gere bugs estranhos, se comporte de maneira confusa para os usuários ou use muitos recursos do sistema Android. Entender o ciclo de vida do Android e responder corretamente às mudanças de estado do ciclo de vida é uma parte importante do desenvolvimento para Android.
Pré-requisitos
- Saber o que é uma atividade e como a criar no app.
- Conhecimento sobre o que o método
onCreate()
da atividade faz e os tipos de operações realizadas nesse método.
O que você vai aprender
- Como mostrar informações de registro no Logcat.
- Os conceitos básicos do ciclo de vida da
Activity
e os callbacks invocados quando a atividade se move entre estados. - Como modificar métodos de callback do ciclo de vida para realizar operações em diferentes momentos do ciclo de vida da atividade.
O que você vai criar
- Como modificar um app inicial chamado "Dessert Clicker" para adicionar informações de registro mostradas no Logcat.
- Como substituir os métodos de callback do ciclo de vida e registrar as mudanças no estado da atividade.
- Como executar o app e anotar as informações de registro que aparecem quando a atividade é iniciada, interrompida e retomada.
- Como implementar
rememberSaveable
para reter os dados do app que podem ser perdidos caso a configuração do dispositivo mude.
2. Visão geral do app
Neste codelab, você vai trabalhar com um app inicial chamado "Dessert Clicker". Nele, sempre que o usuário tocar em uma sobremesa na tela, o app a "compra" para o usuário. O app atualiza valores no layout para:
- O número de sobremesas que foram "compradas".
- A receita total das sobremesas "compradas".
Este app contém vários bugs relacionados ao ciclo de vida do Android. Por exemplo, em algumas circunstâncias, o app redefine os valores das sobremesas para 0. Compreender o ciclo de vida do Android vai ajudar você a entender por que esses problemas ocorrem e como eles podem ser corrigidos.
Baixar o código inicial
No Android Studio, abra a pasta basic-android-kotlin-compose-training-dessert-clicker
.
3. Explorar os métodos do ciclo de vida e adicionar registros básicos
Toda atividade tem um ciclo de vida. Esse termo é uma alusão aos ciclos de vida de vegetais e animais, como o de uma borboleta. Os diferentes estados da borboleta mostram o crescimento dela desde o ovo, passando por lagarta, pupa e borboleta até a morte.
Da mesma forma, o ciclo de vida da atividade consiste nos diferentes estados de uma atividade, desde a primeira inicialização até a destruição, momento em que o sistema operacional (SO) recupera a memória dela. Normalmente, o ponto de entrada de um programa é o método main()
. As atividades do Android, no entanto, começam com o método onCreate()
. Esse método seria o equivalente à fase de ovo no exemplo acima. Você já usou atividades várias vezes ao longo deste curso e talvez reconheça o método onCreate()
. Quando o usuário inicia o app, navega entre atividades, entra e sai do app, a atividade muda de estado.
O diagrama a seguir mostra todos os estados do ciclo de vida da atividade. Como indicado pelos nomes, esses estados representam o status da atividade. Observe que, ao contrário de uma borboleta, uma atividade pode alternar entre os estados ao longo do ciclo de vida, em vez de seguir apenas em uma direção.
Muitas vezes, você quer mudar algum comportamento ou executar um código quando o estado do ciclo de vida da atividade muda. Portanto, a própria classe Activity
e todas as subclasses de Activity
, como ComponentActivity
, implementam um conjunto de métodos de callback do ciclo de vida. O Android invoca esses callbacks quando a atividade se move de um estado para outro, e você pode substituir esses métodos nas suas atividades para realizar tarefas em resposta a essas mudanças de estado do ciclo de vida. O diagrama abaixo mostra os estados do ciclo de vida com os callbacks substituíveis que estão disponíveis.
É importante saber quando o Android invoca os callbacks substituíveis e o que fazer em cada método deles, mas ambos os diagramas são complexos e podem ser confusos. Neste codelab, em vez de apenas ler o que cada estado e callback significam, você vai fazer um trabalho de detetive para entender o ciclo de vida da atividade do Android.
Etapa 1: examinar o método onCreate()
e adicionar registros
Para descobrir o que está acontecendo com o ciclo de vida do Android, é útil saber quando os vários métodos de ciclo de vida são chamados. Essas informações ajudam você a identificar onde algo está errado no app Dessert Clicker.
Uma maneira simples de determinar essas informações é usar a funcionalidade de geração de registros do Android. A geração de registros permite que você escreva mensagens curtas em um console enquanto o app está em execução. Isso pode ser usado para ver quando diferentes callbacks são acionados.
- Execute o app DessertClicker e toque várias vezes na foto de uma sobremesa. Observe como o valor de Desserts sold e o valor total em dólares mudam.
- Abra
MainActivity.kt
e examine o métodoonCreate()
dessa atividade:
override fun onCreate(savedInstanceState: Bundle?) {
// ...
}
No diagrama do ciclo de vida da atividade, talvez você reconheça o método onCreate()
, porque já usou esse callback antes. Ele é o único método que todas as atividades precisam implementar. É no método onCreate()
que você precisa fazer todas as inicializações únicas para a atividade. Por exemplo, em onCreate()
, você chama setContent()
, que especifica o layout da interface da atividade.
O método onCreate()
do ciclo de vida é chamado uma vez, logo após a inicialização da atividade, quando o SO cria o novo objeto Activity
na memória. Depois que onCreate()
é executado, a atividade é considerada criada.
- Adicione a constante a seguir no nível superior do
MainActivity.kt
, acima da declaração de classeclass MainActivity
.
Uma boa prática geral é declarar uma constante TAG
no arquivo, já que o valor dela não vai mudar.
Para a marcar como uma constante de tempo de compilação, use const
ao declarar a variável. Uma constante de tempo de compilação é um valor conhecido durante a compilação.
private const val TAG = "MainActivity"
- No método
onCreate()
, logo após a chamada parasuper.onCreate()
, adicione a seguinte linha:
Log.d(TAG, "onCreate Called")
- Importe a classe
Log
, se necessário (pressioneAlt+Enter
ouOption+Enter
em um Mac e selecione Import). Se você ativou as importações automáticas, isso acontece automaticamente.
import android.util.Log
A classe Log
escreve mensagens no Logcat. O Logcat é o console usado para registrar mensagens. As mensagens do Android sobre seu app são exibidas nesse local, incluindo as mensagens que você envia explicitamente para o registro com o método Log.d()
ou outros métodos da classe Log
.
Há três aspectos importantes da instrução Log
:
- A prioridade da mensagem de registro, ou seja, a importância da mensagem. Nesse caso, o
Log.v()
registra mensagens detalhadas. O métodoLog.d()
escreve uma mensagem de depuração. Outros métodos na classeLog
incluem:Log.i()
para mensagens com informações,Log.w()
para avisos eLog.e()
para mensagens de erros. - O registro
tag
(o primeiro parâmetro). Neste caso,"MainActivity"
. A tag é uma string que facilita a localização de mensagens de registro no Logcat. Normalmente, ela é o nome da classe. - A mensagem de registro chamada
msg
(o segundo parâmetro) é uma string curta. Neste caso,"onCreate Called"
.
- Compile e execute o app Dessert Clicker. Você não vai notar diferenças de comportamento no app quando tocar na sobremesa. No Android Studio, na parte de baixo da tela, clique na guia Logcat.
- Na janela Logcat, digite
tag:MainActivity
no campo de pesquisa.
O Logcat pode ter muitas mensagens, e a maioria delas não é útil para você. É possível filtrar as entradas do Logcat de várias maneiras, mas a pesquisa é a mais fácil. Como você utilizou a MainActivity
como tag de registro no código, é possível usá-la para filtrar o registro. A mensagem de registro inclui a data e a hora, a tag de registro, o nome do pacote (com.example.dessertclicker
) e a mensagem. Como essa mensagem aparece no registro, você sabe que o método onCreate()
foi executado.
Etapa 2: implementar o método onStart()
O método do ciclo de vida onStart()
é chamado logo depois de onCreate()
. Depois que onStart()
é executado, sua atividade fica visível na tela. Ao contrário de onCreate()
, que é chamado apenas uma vez para inicializar a atividade, onStart()
pode ser chamado pelo sistema várias vezes durante o ciclo de vida da atividade.
onStart()
é pareado com um método do ciclo de vida onStop()
correspondente. Se o usuário inicia o app e retorna à tela inicial do dispositivo, a atividade é interrompida e não fica mais visível na tela.
- No Android Studio, com
MainActivity.kt
aberto e o cursor na classeMainActivity
, selecione Code > Override Methods… ou pressioneControl+O
. Uma caixa de diálogo vai aparecer com uma longa lista de todos os métodos que você pode substituir nessa classe.
- Comece a digitar
onStart
para procurar o método correto. Para rolar para o próximo item correspondente, use a seta para baixo. SelecioneonStart()
na lista e clique em OK para inserir o código boilerplate de substituição. O código vai ficar assim:
override fun onStart() {
super.onStart()
}
- No método
onStart()
, adicione uma mensagem de registro:
override fun onStart() {
super.onStart()
Log.d(TAG, "onStart Called")
}
- Compile e execute o app Dessert Clicker e abra o painel do Logcat.
- Digite
tag:MainActivity
no campo de pesquisa para filtrar o registro. Os métodosonCreate()
eonStart()
foram chamados um após o outro, e sua atividade está visível na tela. - Pressione o botão Home no dispositivo e use a tela "Recentes" para retornar à atividade. A atividade continua de onde parou, com todos os mesmos valores, e
onStart()
é registrado uma segunda vez no Logcat. O métodoonCreate()
não é chamado de novo.
2024-04-26 14:54:48.721 5386-5386 MainActivity com.example.dessertclicker D onCreate Called 2024-04-26 14:54:48.756 5386-5386 MainActivity com.example.dessertclicker D onStart Called 2024-04-26 14:55:41.674 5386-5386 MainActivity com.example.dessertclicker D onStart Called
Etapa 3: adicionar mais log statements
Nesta etapa, você vai implementar a geração de registros para todos os outros métodos do ciclo de vida.
- Substitua os métodos restantes do ciclo de vida na
MainActivity
e adicione log statements para cada um, como mostrado neste código:
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume Called")
}
override fun onRestart() {
super.onRestart()
Log.d(TAG, "onRestart Called")
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause Called")
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStop Called")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy Called")
}
- Compile e execute o Dessert Clicker novamente e examine o Logcat.
Desta vez, além de onCreate()
e onStart()
, há uma mensagem de registro para o callback do ciclo de vida de onResume()
.
2024-04-26 14:56:48.684 5484-5484 MainActivity com.example.dessertclicker D onCreate Called 2024-04-26 14:56:48.709 5484-5484 MainActivity com.example.dessertclicker D onStart Called 2024-04-26 14:56:48.713 5484-5484 MainActivity com.example.dessertclicker D onResume Called
Quando uma atividade é iniciada desde o começo, você vê os três callbacks do ciclo de vida chamados nesta ordem:
onCreate()
, quando o sistema cria o app.onStart()
deixa o app visível na tela, mas o usuário ainda não pode interagir com ele.onResume()
coloca o app em primeiro plano, e o usuário agora pode interagir com ele.
Apesar do nome, o método onResume()
é chamado na inicialização, mesmo se não houver nada para retomar.
4. Explorar casos de uso do ciclo de vida
Agora que você configurou o Dessert Clicker para a geração de registros, já pode começar a usar o app e explorar como os callbacks do ciclo de vida são acionados.
Caso de uso 1: como abrir e fechar a atividade
Comece com o caso de uso mais básico, que é iniciar o app pela primeira vez e fechar.
- Compile e execute o app Dessert Clicker, se ele ainda não estiver em execução. Como você viu anteriormente, os callbacks
onCreate()
,onStart()
eonResume()
são chamados quando a atividade é inicializada pela primeira vez.
2024-04-26 14:56:48.684 5484-5484 MainActivity com.example.dessertclicker D onCreate Called 2024-04-26 14:56:48.709 5484-5484 MainActivity com.example.dessertclicker D onStart Called 2024-04-26 14:56:48.713 5484-5484 MainActivity com.example.dessertclicker D onResume Called
- Toque no cupcake algumas vezes.
- Toque no botão Voltar do dispositivo.
No Logcat, onPause()
e onStop()
são chamados nessa ordem.
2024-04-26 14:58:19.984 5484-5484 MainActivity com.example.dessertclicker D onPause Called 2024-04-26 14:58:20.491 5484-5484 MainActivity com.example.dessertclicker D onStop Called 2024-04-26 14:58:20.517 5484-5484 MainActivity com.example.dessertclicker D onDestroy Called
Nesse caso, o uso do botão Voltar faz com que a atividade e o app sejam removidos da tela e movidos para a parte de trás da pilha de atividades.
O SO Android pode fechar a atividade se o código chamar manualmente o método finish()
ou se o usuário forçar o encerramento do app. Por exemplo, o usuário pode forçar o encerramento ou fechar o app na tela "Recentes". O SO também pode encerrar a atividade por conta própria se o app não estiver sendo mostrado na tela há muito tempo. O Android faz isso para preservar a duração da bateria e recuperar os recursos que o app estava usando para que eles fiquem disponíveis a outros apps. Esses são apenas alguns exemplos de por que o sistema Android destrói sua atividade. Há casos adicionais em que o sistema Android destrói sua atividade sem mostrar um aviso.
Caso de uso 2: como sair e voltar à atividade
Agora que você iniciou e fechou o app , já viu a maioria dos estados do ciclo de vida de quando a atividade é criada pela primeira vez. Você também viu a maioria dos estados do ciclo de vida em que a atividade passa quando é fechada. No entanto, à medida que os usuários interagem com dispositivos Android, eles alternam entre apps, voltam para a tela inicial, iniciam novos apps e processam interrupções de outras atividades, como chamadas.
Sua atividade não é fechada totalmente toda vez que o usuário sai dela.
- Quando sua atividade não está mais visível na tela, esse status é conhecido como segundo plano. O oposto disso é quando a atividade está em primeiro plano ou na tela.
- Quando o usuário retorna para o app, a mesma atividade é reiniciada e fica visível novamente. Essa parte do ciclo de vida é chamada de ciclo de vida visível do app.
Quando seu app está em segundo plano, ele geralmente não precisa estar em execução ativamente para preservar os recursos do sistema e a duração da bateria. Use o ciclo de vida e os callbacks da Activity
para saber quando o app está sendo movido para o segundo plano e pausar as operações em andamento. Em seguida, reinicie as operações quando o app for para o primeiro plano.
Nesta etapa, você observa o ciclo de vida da atividade quando o app vai para o segundo plano e retorna ao primeiro plano novamente.
- Quando o app Dessert Clicker estiver em execução, clique no cupcake algumas vezes.
- Pressione o botão home do dispositivo e observe o Logcat no Android Studio. Retornar à tela inicial coloca o app em segundo plano em vez de o encerrar. Os métodos
onPause()
eonStop()
são chamados.
2024-04-26 15:00:04.905 5590-5590 MainActivity com.example.dessertclicker D onPause Called 2024-04-26 15:00:05.430 5590-5590 MainActivity com.example.dessertclicker D onStop Called
Quando onPause()
é chamado, o app não está mais em foco. Depois de onStop()
, o app não fica mais visível na tela. Embora a atividade seja interrompida, o objeto Activity
ainda está na memória em segundo plano. O SO Android não destruiu a atividade. O usuário ainda pode retornar ao app. Dessa forma, o Android guarda os recursos da atividade.
- Use a tela "Recentes" para retornar ao app. No emulador, essa tela pode ser acessada pelo botão quadrado do sistema, mostrado na imagem abaixo.
No Logcat, a atividade é reiniciada por onRestart()
e onStart()
e depois é retomada por onResume()
.
2024-04-26 15:00:39.371 5590-5590 MainActivity com.example.dessertclicker D onRestart Called 2024-04-26 15:00:39.372 5590-5590 MainActivity com.example.dessertclicker D onStart Called 2024-04-26 15:00:39.374 5590-5590 MainActivity com.example.dessertclicker D onResume Called
Quando a atividade retorna para o primeiro plano, o método onCreate()
não é chamado novamente. O objeto da atividade não foi destruído, por isso não precisa ser criado novamente. O método onRestart()
é chamado em vez de onCreate()
. Desta vez, quando a atividade retornar ao primeiro plano, o número de Desserts sold é mantido.
- Inicie pelo menos um app que não seja o Dessert Clicker para que o dispositivo tenha alguns apps na tela "Recentes".
- Vá até a tela "Recentes" e abra outra atividade recente. Depois, volte para a tela de apps recentes e mova o Dessert Clicker para o primeiro plano.
Os mesmos callbacks vão aparecer no Logcat, como ao pressionar o botão Home. onPause()
e onStop()
são chamados quando o app entra em segundo plano. Depois, onRestart()
, onStart()
e onResume()
são chamados quando ele volta ao primeiro plano.
Esses métodos são chamados quando o app é interrompido e passa para o segundo plano ou quando ele é reiniciado e volta para o primeiro plano. Se for necessário realizar alguma tarefa no app nesses casos, modifique o método de callback do ciclo de vida relevante.
Caso de uso 3: ocultar parcialmente a atividade
Você aprendeu que, quando um app é iniciado e onStart()
é chamado, ele fica visível na tela. Quando onResume()
é chamado, o app recebe o foco do usuário, ou seja, o usuário pode interagir com o app. A parte do ciclo de vida em que o app está totalmente na tela e com foco do usuário é conhecida como ciclo de vida em primeiro plano.
Quando o app é movido para segundo plano, o foco é perdido após onPause()
, e o app não fica visível após onStop()
.
A diferença entre foco e visibilidade é importante. É possível que uma atividade fique parcialmente visível na tela, mas não tenha o foco do usuário. Nesta etapa, você vai ver um caso em que uma atividade está parcialmente visível, mas não tem o foco do usuário.
- Com o app Dessert Clicker em execução, clique no botão Share na parte superior direita da tela.
A atividade de compartilhamento vai aparecer na metade de baixo da tela, mas a atividade do app ainda ficará visível na metade de cima.
- Analise o Logcat e observe que apenas o
onPause()
foi chamado.
2024-04-26 15:01:49.535 5590-5590 MainActivity com.example.dessertclicker D onPause Called
Neste caso de uso, onStop()
não é chamado, porque a atividade ainda está parcialmente visível. Mas ela não tem o foco do usuário, e não é possível interagir com ela. A atividade de "compartilhamento" que está em primeiro plano tem o foco do usuário.
Por que essa diferença é importante? O método onPause()
geralmente interrompe a atividade apenas por um curto período antes de o usuário retornar para ela ou navegar para outra atividade ou app. Geralmente, é recomendável continuar atualizando a IU para que o restante do app não pareça travar.
O código executado no método onPause()
bloqueia a exibição de outros elementos. Portanto, use um código leve em onPause()
. Por exemplo, se o usuário receber uma chamada, o código no onPause()
pode atrasar a notificação da chamada recebida.
- Clique fora da caixa de diálogo de compartilhamento para retornar ao app. Observe que o
onResume()
é chamado.
Tanto onResume()
quanto onPause()
estão relacionados ao foco. O método onResume()
é chamado quando a atividade tem o foco, e onPause()
é chamado quando a atividade perde o foco.
5. Explorar mudanças de configuração
Há outro caso no gerenciamento do ciclo de vida da atividade que é importante entender: como as mudanças de configuração afetam o ciclo de vida das suas atividades.
Uma mudança de configuração ocorre quando o estado do dispositivo muda de forma tão radical que a maneira mais fácil do sistema resolver a mudança é encerrar completamente e recriar a atividade. Por exemplo, se o usuário muda o idioma do dispositivo, todo o layout pode ser alterado para acomodar diferentes direções de texto e comprimentos de string. Se o usuário conecta o dispositivo a uma base ou adiciona um teclado físico, o layout do app pode usar um layout ou tamanho de exibição diferente. E se a orientação do dispositivo mudar (se ele é girado do modo retrato para paisagem ou vice-versa), é possível que o layout mude para se ajustar à nova orientação. Vejamos como o app se comporta nesse caso.
O último callback do ciclo de vida a ser demonstrado é onDestroy()
, que é chamado depois de onStop()
. Ele é chamado pouco antes de a atividade ser destruída. Isso pode acontecer quando o código do app chama finish()
ou o sistema precisa destruir e recriar a atividade devido a uma mudança de configuração.
A mudança de configuração faz com que onDestroy()
seja chamado.
A rotação da tela é um tipo de mudança de configuração que faz com que a atividade seja encerrada e reiniciada. Para simular essa mudança e examinar os efeitos dela, conclua as seguintes etapas:
- Compile e execute seu app.
- Verifique se o bloqueio de rotação de tela no emulador está desativado.
- Gire o dispositivo ou o emulador para o modo paisagem. Você pode girar o emulador para a esquerda ou direita usando os botões de rotação.
- Analise o Logcat e entenda que, quando a atividade é encerrada, ele chama
onPause()
,onStop()
eonDestroy()
, nessa ordem.
2024-04-26 15:03:32.183 5716-5716 MainActivity com.example.dessertclicker D onPause Called 2024-04-26 15:03:32.185 5716-5716 MainActivity com.example.dessertclicker D onStop Called 2024-04-26 15:03:32.205 5716-5716 MainActivity com.example.dessertclicker D onDestroy Called
Perda de dados durante a rotação do dispositivo
- Compile e execute seu app, depois abra o Logcat.
- Clique no cupcake algumas vezes e observe que as sobremesas vendidas e a receita total não são zero.
- Verifique se o bloqueio de rotação de tela no emulador está desativado.
- Gire o dispositivo ou o emulador para o modo paisagem. Você pode girar o emulador para a esquerda ou direita usando os botões de rotação.
- Analise a saída no Logcat. Filtre a saída na
MainActivity
.
2024-04-26 15:04:29.356 5809-5809 MainActivity com.example.dessertclicker D onCreate Called 2024-04-26 15:04:29.378 5809-5809 MainActivity com.example.dessertclicker D onStart Called 2024-04-26 15:04:29.382 5809-5809 MainActivity com.example.dessertclicker D onResume Called 2024-04-26 15:06:52.168 5809-5809 MainActivity com.example.dessertclicker D onPause Called 2024-04-26 15:06:52.183 5809-5809 MainActivity com.example.dessertclicker D onStop Called 2024-04-26 15:06:52.219 5809-5809 MainActivity com.example.dessertclicker D onDestroy Called 2024-04-26 15:06:52.302 5809-5809 MainActivity com.example.dessertclicker D onCreate Called 2024-04-26 15:06:52.308 5809-5809 MainActivity com.example.dessertclicker D onStart Called 2024-04-26 15:06:52.312 5809-5809 MainActivity com.example.dessertclicker D onResume Called
Quando o dispositivo ou emulador gira a tela, o sistema chama todos os callbacks do ciclo de vida para encerrar a atividade. Em seguida, enquanto a atividade é recriada, o sistema chama todos os callbacks do ciclo de vida para iniciá-la.
Quando o dispositivo é girado e a atividade é encerrada e recriada, ela é reiniciada com valores padrão. Ou seja, a imagem da sobremesa, o número de sobremesas vendidas e a receita são redefinidos como zero.
Para saber por que esses valores estão sendo redefinidos e como os corrigir, você precisa aprender sobre o ciclo de vida de uma função de composição e como ela sabe observar e manter o respectivo estado.
Ciclo de vida de um elemento combinável
A IU do app é criada inicialmente pela execução de funções de composição em um processo chamado "Composição".
Quando o estado do app muda, uma recomposição é agendada. A recomposição acontece quando o Compose executa novamente as funções combináveis que podem ter mudado de estado e cria uma interface atualizada. A composição é atualizada para refletir essas mudanças.
A única maneira de criar ou atualizar uma composição é pela composição inicial dela e pelas recomposições subsequentes.
As funções de composição têm um ciclo de vida próprio que é independente do ciclo de vida da atividade. O ciclo de vida delas é composto pelos seguintes eventos: entrar na composição, recompor 0 ou mais vezes e, depois, sair da composição.
Para que o Compose acompanhe e acione uma recomposição, ele precisa saber quando o estado mudou. Para indicar ao Compose que ele precisa rastrear o estado de um objeto, o objeto precisa ser do tipo State
ou MutableState
. O tipo State
é imutável e só pode ser lido. Um tipo MutableState
é mutável e permite leituras e gravações.
Você já viu e usou o MutableState
no app Lemonade e no app Tip Time em codelabs anteriores.
Para criar a variável mutável revenue
, declare-a usando mutableStateOf
. 0
é o valor padrão inicial.
var revenue = mutableStateOf(0)
Embora isso seja suficiente para que o Compose acione uma recomposição quando o valor da receita mudar, não basta manter o valor atualizado. Sempre que o elemento combinável for executado novamente, ele vai reinicializar o valor da receita para o valor padrão inicial de 0
.
Para instruir o Compose a reter e reutilizar o valor durante as recomposições, é necessário declarar o valor com a API remember
.
var revenue by remember { mutableStateOf(0) }
Se o valor de revenue
mudar, o Compose vai programar a recomposição de todas as funções de composição que leem esse valor.
Embora o Compose lembre o estado da receita durante as recomposições, ele não retém esse estado durante uma mudança de configuração. Para que o Compose retenha o estado durante uma mudança de configuração, use rememberSaveable
.
Para mais informações e práticas recomendadas, consulte o codelab Introdução ao estado no Compose.
Usar rememberSaveable
para salvar valores em todas as mudanças de configuração
Use a função rememberSaveable
para salvar os valores necessários se o SO Android destruir e recriar a atividade.
Para salvar valores durante as recomposições, é necessário usar remember
. Use rememberSaveable
para salvar valores durante recomposições E mudanças de configuração.
Salvar o valor usando rememberSaveable
garante que ele esteja disponível quando a atividade for restaurada, se necessário.
- No
MainActivity
, atualize o grupo de cinco variáveis que atualmente usamremember
pararememberSaveable
.
var revenue by remember { mutableStateOf(0) }
...
var currentDessertImageId by remember {
mutableStateOf(desserts[currentDessertIndex].imageId)
}
var revenue by rememberSaveable { mutableStateOf(0) }
...
var currentDessertImageId by rememberSaveable {
mutableStateOf(desserts[currentDessertIndex].imageId)
}
- Compile e execute seu app.
- Clique no cupcake algumas vezes e observe que as sobremesas vendidas e a receita total não são zero.
- Gire o dispositivo ou o emulador para o modo paisagem.
- Observe que, depois que a atividade é destruída e recriada, a imagem da sobremesa, as sobremesas vendidas e a receita total são restauradas para os valores anteriores.
6. Código da solução
7. Resumo
Ciclo de vida da atividade
- O ciclo de vida da atividade é um conjunto de estados pelos quais uma atividade passa. Ele começa quando o SO Android cria a atividade pela primeira vez e termina quando ele a destrói.
- Quando o usuário navega entre as atividades e dentro e fora do app, cada atividade se move entre os estados do ciclo de vida da atividade.
- Cada estado do ciclo de vida da atividade tem um método de callback correspondente que você pode modificar na classe
Activity
. O conjunto principal de métodos do ciclo de vida é:onCreate()
,onRestart()
,onStart()
,onResume()
,onPause()
,onStop()
,onDestroy()
. - Para adicionar um comportamento que ocorre quando a atividade passa para um estado do ciclo de vida, substitua o método de callback do estado.
- Para adicionar o esqueleto de métodos de substituição às classes no Android Studio, selecione Code > Override Methods… ou pressione
Control+O
.
Geração de registros com a classe Log
- A API Android Logging e especificamente a classe
Log
permitem escrever mensagens curtas que são exibidas no Logcat no Android Studio. - Use
Log.d()
para escrever uma mensagem de depuração. Esse método recebe dois argumentos: a tag log, que geralmente é o nome da classe, e a mensagem log, uma string curta. - Use a janela Logcat do Android Studio para ver os registros do sistema, incluindo as mensagens que você escrever.
Mudanças de configuração
- Uma mudança de configuração ocorre quando o estado do dispositivo muda de forma tão radical que a maneira mais fácil do sistema resolver a mudança é destruir e recriar a atividade.
- O exemplo mais comum de uma mudança de configuração é quando o usuário gira o dispositivo do modo de retrato para o de paisagem ou vice-versa. Uma mudança de configuração também pode ocorrer quando o idioma do dispositivo muda ou quando o usuário conecta um teclado físico.
- Quando uma mudança de configuração ocorre, o Android invoca todos os callbacks de desligamento do ciclo de vida da atividade. O Android reinicia a atividade do zero, executando todos os callbacks de inicialização do ciclo de vida.
- Quando o Android encerra um app devido a uma mudança de configuração, ele reinicia a atividade usando
onCreate()
. - Para salvar um valor que precisa sobreviver a uma mudança de configuração, declare as variáveis dele com
rememberSaveable
.