Ciclo de vida de atividade
As atividades são um bloco de construção fundamental de aplicativos Android e podem existir em vários estados diferentes. O ciclo de vida da atividade começa com instanciação e termina com destruição e inclui muitos estados no meio. Quando uma atividade muda de estado, o método de evento de ciclo de vida apropriado é chamado, notificando a atividade da alteração de estado iminente e permitindo que ele execute o código para se adaptar a essa alteração. Este artigo examina o ciclo de vida das atividades e explica a responsabilidade que uma atividade tem durante cada uma dessas alterações de estado para fazer parte de um aplicativo confiável e bem comportado.
Visão geral do ciclo de vida da atividade
As atividades são um conceito de programação incomum específico do Android. No desenvolvimento de aplicativos tradicional, geralmente há um método de main estático, que é executado para iniciar o aplicativo. Com o Android, no entanto, as coisas são diferentes; Os aplicativos Android podem ser iniciados por meio de qualquer atividade registrada em um aplicativo. Na prática, a maioria dos aplicativos terá apenas uma atividade específica especificada como o ponto de entrada do aplicativo. No entanto, se um aplicativo falhar ou for encerrado pelo sistema operacional, o sistema operacional poderá tentar reiniciar o aplicativo na última atividade aberta ou em qualquer outro lugar na pilha de atividades anterior. Além disso, o sistema operacional poderá pausar as atividades quando elas não estiverem ativas e recuperá-las se estiver com pouca memória. Deve ser feita uma consideração cuidadosa para permitir que o aplicativo restaure corretamente seu estado caso uma atividade seja reiniciada, especialmente se essa atividade depender de dados de atividades anteriores.
O ciclo de vida da atividade é implementado como uma coleção de métodos que o sistema operacional chama durante todo o ciclo de vida de uma atividade. Esses métodos permitem que os desenvolvedores implementem a funcionalidade necessária para atender aos requisitos de gerenciamento de recursos e estado de seus aplicativos.
É extremamente importante que o desenvolvedor de aplicativos analise os requisitos de cada atividade para determinar quais métodos expostos pelo ciclo de vida da atividade precisam ser implementados. A falha em fazer isso pode resultar em instabilidade do aplicativo, falhas, bloat de recursos e, possivelmente, até mesmo instabilidade subjacente do sistema operacional.
Este capítulo examina detalhadamente o ciclo de vida da atividade, incluindo:
- Estados de atividade
- Métodos de ciclo de vida
- Retendo o estado de um aplicativo
Esta seção também inclui um passo a passo que fornece exemplos práticos sobre como salvar o estado com eficiência durante o ciclo de vida da atividade. Ao final deste capítulo, você deve ter uma compreensão do ciclo de vida da atividade e como dar suporte a ele em um aplicativo Android.
Ciclo de vida de atividade
O ciclo de vida da atividade do Android compreende uma coleção de métodos expostos na classe Activity que fornecem ao desenvolvedor uma estrutura de gerenciamento de recursos. Essa estrutura permite que os desenvolvedores atendam aos requisitos exclusivos de gerenciamento de estado de cada atividade em um aplicativo e lidem corretamente com o gerenciamento de recursos.
Estados de atividade
O sistema operacional Android arbitra Atividades com base em seu estado. Isso ajuda o Android a identificar atividades que não estão mais em uso, permitindo que o sistema operacional recupere memória e recursos. O diagrama a seguir ilustra os estados pelos quais uma Atividade pode passar durante seu tempo de vida:
Esses estados podem ser divididos em quatro grupos de main da seguinte maneira:
Ativo ou Em execução – as atividades são consideradas ativas ou em execução se estiverem em primeiro plano, também conhecidas como a parte superior da pilha de atividades. Essa é considerada a atividade de prioridade mais alta no Android e, como tal, só será eliminada pelo sistema operacional em situações extremas, como se a atividade tentar usar mais memória do que está disponível no dispositivo, pois isso poderia fazer com que a interface do usuário ficasse sem resposta.
Pausada – quando o dispositivo entra em suspensão ou uma atividade ainda está visível, mas parcialmente oculta por uma atividade nova, não completa ou transparente, a atividade é considerada pausada. As atividades pausadas ainda estão ativas, ou seja, mantêm todas as informações de estado e membro e permanecem anexadas ao gerenciador de janelas. Essa é considerada a segunda atividade de prioridade mais alta no Android e, como tal, só será eliminada pelo sistema operacional se a execução dessa atividade atender aos requisitos de recursos necessários para manter a Atividade Ativa/Em Execução estável e responsiva.
Parado/em segundo plano – atividades que são completamente obscurecidas por outra atividade são consideradas interrompidas ou em segundo plano. As atividades interrompidas ainda tentam manter suas informações de estado e membro pelo maior tempo possível, mas as atividades interrompidas são consideradas a prioridade mais baixa dos três estados e, como tal, o sistema operacional encerrará as atividades nesse estado primeiro para atender aos requisitos de recursos das atividades de prioridade mais alta.
Reiniciado – é possível que uma atividade que está em qualquer lugar de pausada seja interrompida no ciclo de vida seja removida da memória pelo Android. Se o usuário navegar de volta para a atividade, ele deverá ser reiniciado, restaurado para o estado salvo anteriormente e exibido para o usuário.
Atividade Re-Creation em resposta a alterações de configuração
Para tornar as coisas mais complicadas, o Android lança mais uma chave inglesa na mistura chamada Alterações de Configuração. As alterações de configuração são ciclos rápidos de destruição/recriação de atividades que ocorrem quando a configuração de uma atividade é alterada, como quando o dispositivo é girado (e a atividade precisa ser recriada no modo paisagem ou retrato), quando o teclado é exibido (e a atividade é apresentada com a oportunidade de redimensionar a si mesmo) ou quando o dispositivo é colocado em um dock, entre outros.
As alterações de configuração ainda causam as mesmas alterações de Estado de Atividade que ocorreriam durante a interrupção e a reinicialização de uma atividade. No entanto, para garantir que um aplicativo se sinta responsivo e tenha um bom desempenho durante as alterações de configuração, é importante que eles sejam tratados o mais rápido possível. Por isso, o Android tem uma API específica que pode ser usada para persistir o estado durante as alterações de configuração. Abordaremos isso posteriormente na seção Gerenciando estado ao longo do ciclo de vida .
Métodos de ciclo de vida da atividade
O SDK do Android e, por extensão, a estrutura Xamarin.Android fornecem um modelo avançado para gerenciar o estado das atividades em um aplicativo. Quando o estado de uma atividade é alterado, a atividade é notificada pelo sistema operacional, que chama métodos específicos nessa atividade. O diagrama a seguir ilustra esses métodos em relação ao Ciclo de Vida da Atividade:
Como desenvolvedor, você pode lidar com alterações de estado substituindo esses métodos em uma atividade. No entanto, é importante observar que todos os métodos de ciclo de vida são chamados no thread da interface do usuário e impedirão que o sistema operacional execute a próxima parte do trabalho da interface do usuário, como ocultar a atividade atual, exibir uma nova atividade etc. Dessa forma, o código nesses métodos deve ser o mais breve possível para fazer com que um aplicativo se sinta bem com o desempenho. Todas as tarefas de execução prolongada devem ser executadas em um thread em segundo plano.
Vamos examinar cada um desses métodos de ciclo de vida e seu uso:
OnCreate
OnCreate é o primeiro método a ser chamado quando uma atividade é criada.
OnCreate
é sempre substituído para executar as inicializações de inicialização que podem ser exigidas por uma Atividade como:
- Criando exibições
- Como inicializar variáveis
- Associar dados estáticos a listas
OnCreate
usa um parâmetro Bundle , que é um dicionário para armazenar e transmitir informações de estado e objetos entre atividades Se o pacote não for nulo, isso indica que a atividade está sendo reiniciada e deve restaurar seu estado da instância anterior. O código a seguir ilustra como recuperar valores do pacote:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
string intentString;
bool intentBool;
if (bundle != null)
{
intentString = bundle.GetString("myString");
intentBool = bundle.GetBoolean("myBool");
}
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
}
Depois de OnCreate
concluído, o Android chamará OnStart
.
OnStart
OnStart é sempre chamado pelo sistema após OnCreate
a conclusão. As atividades poderão substituir esse método se precisarem executar tarefas específicas antes que uma atividade se torne visível, como atualizar valores atuais de exibições dentro da atividade. O Android chamará OnResume
imediatamente após esse método.
OnResume
O sistema chama OnResume quando a Atividade está pronta para começar a interagir com o usuário. As atividades devem substituir esse método para executar tarefas como:
- Aumentando as taxas de quadros (uma tarefa comum no desenvolvimento de jogos)
- Iniciando animações
- Escutando atualizações de GPS
- Exibir alertas ou caixas de diálogo relevantes
- Conectar manipuladores de eventos externos
Por exemplo, o snippet de código a seguir mostra como inicializar a câmera:
protected override void OnResume()
{
base.OnResume(); // Always call the superclass first.
if (_camera==null)
{
// Do camera initializations here
}
}
OnResume
é importante porque qualquer operação feita em OnPause
deve ser desfeito no OnResume
, já que é o único método de ciclo de vida que tem a garantia de ser executado depois OnPause
de trazer a atividade de volta à vida útil.
Onpause
OnPause é chamado quando o sistema está prestes a colocar a atividade em segundo plano ou quando a atividade fica parcialmente obscurecida. As atividades devem substituir esse método se precisarem:
Confirmar alterações não salvas em dados persistentes
Destruir ou limpo outros objetos que consomem recursos
Reduzir as taxas de quadros e pausar animações
Cancelar o registro de manipuladores de eventos externos ou manipuladores de notificação (ou seja, aqueles que estão vinculados a um serviço). Isso deve ser feito para evitar vazamentos de memória de atividade.
Da mesma forma, se a Atividade tiver exibido diálogos ou alertas, eles deverão ser limpos com o
.Dismiss()
método .
Por exemplo, o snippet de código a seguir liberará a câmera, pois a Atividade não pode fazer uso dela enquanto estiver em pausa:
protected override void OnPause()
{
base.OnPause(); // Always call the superclass first
// Release the camera as other activities might need it
if (_camera != null)
{
_camera.Release();
_camera = null;
}
}
Há dois métodos possíveis de ciclo de vida que serão chamados após OnPause
:
-
OnResume
será chamado se a Atividade for retornada para o primeiro plano. -
OnStop
será chamado se a Atividade estiver sendo colocada em segundo plano.
OnStop
OnStop é chamado quando a atividade não está mais visível para o usuário. Isso acontece quando ocorre um dos seguintes procedimentos:
- Uma nova atividade está sendo iniciada e está encobrindo essa atividade.
- Uma atividade existente está sendo trazida para o primeiro plano.
- A atividade está sendo destruída.
OnStop
nem sempre pode ser chamado em situações de memória insuficiente, como quando o Android está faminto por recursos e não pode usar corretamente em segundo plano a Atividade. Por esse motivo, é melhor não depender de OnStop
ser chamado ao preparar uma Atividade para destruição. Os próximos métodos de ciclo de vida que podem ser chamados após esse serão OnDestroy
se a Atividade estiver desaparecendo ou OnRestart
se a Atividade estiver voltando para interagir com o usuário.
Ondestroy
OnDestroy é o método final que é chamado em uma instância de Atividade antes de ser destruída e completamente removida da memória. Em situações extremas, o Android pode encerrar o processo de aplicativo que está hospedando a Atividade, o que resultará em OnDestroy
não ser invocado. A maioria das atividades não implementará esse método porque a maioria limpo e desligar foi feita nos OnPause
métodos e OnStop
. O OnDestroy
método normalmente é substituído para limpo tarefas de execução longa que podem vazar recursos. Um exemplo disso pode ser threads em segundo plano que foram iniciados no OnCreate
.
Não haverá métodos de ciclo de vida chamados depois que a Atividade tiver sido destruída.
OnRestart
OnRestart é chamado depois que sua atividade é interrompida, antes de ser iniciada novamente. Um bom exemplo disso seria quando o usuário pressionasse o botão página inicial durante uma atividade no aplicativo. Quando isso acontece OnPause
e, em seguida OnStop
, os métodos são chamados e a Atividade é movida para o segundo plano, mas não é destruída. Se o usuário restaurar o aplicativo usando o gerenciador de tarefas ou um aplicativo semelhante, o Android chamará o OnRestart
método da atividade.
Não há diretrizes gerais para que tipo de lógica deve ser implementado no OnRestart
. Isso ocorre porque OnStart
é sempre invocado independentemente de a Atividade estar sendo criada ou sendo reiniciada, portanto, todos os recursos exigidos pela Atividade devem ser inicializados em , em OnStart
vez de OnRestart
.
O próximo método de ciclo de vida chamado depois OnRestart
será OnStart
.
Voltar vs. Página Inicial
Muitos dispositivos Android têm dois botões distintos: um botão "Voltar" e um botão "Página Inicial". Um exemplo disso pode ser visto na seguinte captura de tela do Android 4.0.3:
Há uma diferença sutil entre os dois botões, mesmo que eles pareçam ter o mesmo efeito de colocar um aplicativo em segundo plano. Quando um usuário clica no botão Voltar, ele está informando ao Android que ele terminou a atividade. O Android destruirá a Atividade. Por outro lado, quando o usuário clica no botão Página Inicial, a atividade é simplesmente colocada em segundo plano – o Android não encerrará a atividade.
Gerenciando o estado durante todo o ciclo de vida
Quando uma atividade é interrompida ou destruída, o sistema oferece uma oportunidade de salvar o estado da Atividade para reidratação posterior. Esse estado salvo é chamado de estado de instância. O Android fornece três opções para armazenar o estado da instância durante o ciclo de vida da atividade:
Armazenar valores primitivos em um
Dictionary
conhecido como um Pacote que o Android usará para salvar o estado.Criar uma classe personalizada que conterá valores complexos, como bitmaps. O Android usará essa classe personalizada para salvar o estado.
Contornar o ciclo de vida da alteração de configuração e assumir total responsabilidade pela manutenção do estado na atividade.
Este guia aborda as duas primeiras opções.
Estado do Pacote
A principal opção para salvar o estado da instância é usar um objeto de dicionário de chave/valor conhecido como pacote.
Lembre-se de que quando uma Atividade é criada que o OnCreate
método é passado um pacote como um parâmetro, esse pacote pode ser usado para restaurar o estado da instância. Não é recomendável usar um pacote para dados mais complexos que não serão serializados de forma rápida ou fácil para pares chave/valor (como bitmaps); em vez disso, ele deve ser usado para valores simples como cadeias de caracteres.
Uma Atividade fornece métodos para ajudar a salvar e recuperar o estado da instância no Pacote:
OnSaveInstanceState – isso é invocado pelo Android quando a atividade está sendo destruída. As atividades poderão implementar esse método se precisarem persistir qualquer item de estado de chave/valor.
OnRestoreInstanceState – isso é chamado depois que o
OnCreate
método é concluído e fornece outra oportunidade para uma Atividade restaurar seu estado após a conclusão da inicialização.
O diagrama a seguir ilustra como esses métodos são usados:
OnSaveInstanceState
OnSaveInstanceState será chamado, pois a atividade está sendo interrompida. Ele receberá um parâmetro de pacote no qual a Atividade pode armazenar seu estado. Quando um dispositivo experimenta uma alteração de configuração, uma Atividade pode usar o Bundle
objeto que é passado para preservar o estado atividade substituindo OnSaveInstanceState
. Por exemplo, considere o seguinte código:
int c;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
this.SetContentView (Resource.Layout.SimpleStateView);
var output = this.FindViewById<TextView> (Resource.Id.outputText);
if (bundle != null) {
c = bundle.GetInt ("counter", -1);
} else {
c = -1;
}
output.Text = c.ToString ();
var incrementCounter = this.FindViewById<Button> (Resource.Id.incrementCounter);
incrementCounter.Click += (s,e) => {
output.Text = (++c).ToString();
};
}
O código acima incrementa um inteiro chamado c
quando um botão chamado incrementCounter
é clicado, exibindo o resultado em um TextView
chamado output
. Quando ocorre uma alteração de configuração, por exemplo, quando o dispositivo é girado, o código acima perde o valor de c
porque o bundle
seria null
, conforme mostrado na figura abaixo:
Para preservar o valor de c
neste exemplo, a Atividade pode substituir OnSaveInstanceState
, salvando o valor no pacote, conforme mostrado abaixo:
protected override void OnSaveInstanceState (Bundle outState)
{
outState.PutInt ("counter", c);
base.OnSaveInstanceState (outState);
}
Agora, quando o dispositivo é girado para uma nova orientação, o inteiro é salvo no pacote e é recuperado com a linha :
c = bundle.GetInt ("counter", -1);
Observação
É importante sempre chamar a implementação base de OnSaveInstanceState
para que o estado da hierarquia de exibição também possa ser salvo.
Estado de Exibição
OnSaveInstanceState
Substituir é um mecanismo apropriado para salvar dados transitórios em uma Atividade entre alterações de orientação, como o contador no exemplo acima. No entanto, a implementação padrão de OnSaveInstanceState
cuidará de salvar dados transitórios na interface do usuário para cada exibição, desde que cada exibição tenha uma ID atribuída. Por exemplo, digamos que um aplicativo tenha um EditText
elemento definido em XML da seguinte maneira:
<EditText android:id="@+id/myText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
Como o EditText
controle tem um id
atribuído, quando o usuário insere alguns dados e gira o dispositivo, os dados ainda são exibidos, conforme mostrado abaixo:
OnRestoreInstanceState
OnRestoreInstanceState será chamado após OnStart
. Ele fornece a uma atividade a oportunidade de restaurar qualquer estado que foi salvo anteriormente em um Pacote durante o anterior OnSaveInstanceState
. No entanto, esse é o mesmo pacote fornecido para OnCreate
.
O código a seguir demonstra como o estado pode ser restaurado em OnRestoreInstanceState
:
protected override void OnRestoreInstanceState(Bundle savedState)
{
base.OnRestoreInstanceState(savedState);
var myString = savedState.GetString("myString");
var myBool = savedState.GetBoolean("myBool");
}
Esse método existe para fornecer alguma flexibilidade em torno de quando o estado deve ser restaurado. Às vezes, é mais apropriado aguardar até que todas as inicializações sejam feitas antes de restaurar o estado da instância. Além disso, uma subclasse de uma Atividade existente pode querer apenas restaurar determinados valores do estado da instância. Em muitos casos, não é necessário substituir OnRestoreInstanceState
, pois a maioria das atividades pode restaurar o estado usando o pacote fornecido para OnCreate
.
Para obter um exemplo de como salvar o estado usando um Bundle
, consulte o passo a passo – salvando o estado atividade.
Limitações do pacote
Embora OnSaveInstanceState
facilite o salvamento de dados transitórios, ele tem algumas limitações:
Não é chamado em todos os casos. Por exemplo, pressionar Home ou Back para sair de uma Atividade não resultará em
OnSaveInstanceState
ser chamado.O pacote passado para
OnSaveInstanceState
não foi projetado para objetos grandes, como imagens. No caso de objetos grandes, é preferível salvar o objeto de OnRetainNonConfigurationInstance , conforme discutido abaixo.Os dados salvos usando o pacote são serializados, o que pode levar a atrasos.
O estado do pacote é útil para dados simples que não usam muita memória, enquanto os dados de instância de não configuração são úteis para dados mais complexos ou dados que são caros de recuperar, como de uma chamada de serviço Web ou de uma consulta de banco de dados complicada. Os dados da instância de não configuração são salvos em um objeto conforme necessário. A próxima seção apresenta como uma forma de preservar tipos de dados mais complexos OnRetainNonConfigurationInstance
por meio de alterações de configuração.
Persistindo dados complexos
Além de persistir dados no pacote, o Android também dá suporte ao salvamento de dados substituindo OnRetainNonConfigurationInstance e retornando uma instância de um Java.Lang.Object
que contém os dados a serem persistidos. Há dois benefícios principais de usar OnRetainNonConfigurationInstance
para salvar o estado:
O objeto retornado de tem um bom desempenho com tipos de
OnRetainNonConfigurationInstance
dados maiores e mais complexos porque a memória retém esse objeto.O
OnRetainNonConfigurationInstance
método é chamado sob demanda e somente quando necessário. Isso é mais econômico do que usar um cache manual.
Usar OnRetainNonConfigurationInstance
é adequado para cenários em que é caro recuperar os dados várias vezes, como em chamadas de serviço Web. Por exemplo, considere o seguinte código que pesquisa o Twitter:
public class NonConfigInstanceActivity : ListActivity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
SearchTwitter ("xamarin");
}
public void SearchTwitter (string text)
{
string searchUrl = String.Format("http://search.twitter.com/search.json?" + "q={0}&rpp=10&include_entities=false&" + "result_type=mixed", text);
var httpReq = (HttpWebRequest)HttpWebRequest.Create (new Uri (searchUrl));
httpReq.BeginGetResponse (new AsyncCallback (ResponseCallback), httpReq);
}
void ResponseCallback (IAsyncResult ar)
{
var httpReq = (HttpWebRequest)ar.AsyncState;
using (var httpRes = (HttpWebResponse)httpReq.EndGetResponse (ar)) {
ParseResults (httpRes);
}
}
void ParseResults (HttpWebResponse httpRes)
{
var s = httpRes.GetResponseStream ();
var j = (JsonObject)JsonObject.Load (s);
var results = (from result in (JsonArray)j ["results"] let jResult = result as JsonObject select jResult ["text"].ToString ()).ToArray ();
RunOnUiThread (() => {
PopulateTweetList (results);
});
}
void PopulateTweetList (string[] results)
{
ListAdapter = new ArrayAdapter<string> (this, Resource.Layout.ItemView, results);
}
}
Esse código recupera resultados da Web formatados como JSON, analisa-os e apresenta os resultados em uma lista, conforme mostrado na captura de tela a seguir:
Quando ocorre uma alteração de configuração , por exemplo, quando um dispositivo é girado - o código repete o processo. Para reutilizar os resultados originalmente recuperados e não causar chamadas de rede desnecessárias e redundantes, podemos usar OnRetainNonconfigurationInstance
para salvar os resultados, conforme mostrado abaixo:
public class NonConfigInstanceActivity : ListActivity
{
TweetListWrapper _savedInstance;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
var tweetsWrapper = LastNonConfigurationInstance as TweetListWrapper;
if (tweetsWrapper != null) {
PopulateTweetList (tweetsWrapper.Tweets);
} else {
SearchTwitter ("xamarin");
}
public override Java.Lang.Object OnRetainNonConfigurationInstance ()
{
base.OnRetainNonConfigurationInstance ();
return _savedInstance;
}
...
void PopulateTweetList (string[] results)
{
ListAdapter = new ArrayAdapter<string> (this, Resource.Layout.ItemView, results);
_savedInstance = new TweetListWrapper{Tweets=results};
}
}
Agora, quando o dispositivo é girado, os resultados originais são recuperados da LastNonConfiguartionInstance
propriedade . Neste exemplo, os resultados consistem em um string[]
que contém tweets. Como OnRetainNonConfigurationInstance
exige que um Java.Lang.Object
seja retornado, o string[]
é encapsulado em uma classe que subclasse Java.Lang.Object
, conforme mostrado abaixo:
class TweetListWrapper : Java.Lang.Object
{
public string[] Tweets { get; set; }
}
Por exemplo, tentar usar um TextView
como o objeto retornado de OnRetainNonConfigurationInstance
vazará a Atividade, conforme ilustrado pelo código abaixo:
TextView _textView;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
var tv = LastNonConfigurationInstance as TextViewWrapper;
if(tv != null) {
_textView = tv;
var parent = _textView.Parent as FrameLayout;
parent.RemoveView(_textView);
} else {
_textView = new TextView (this);
_textView.Text = "This will leak.";
}
SetContentView (_textView);
}
public override Java.Lang.Object OnRetainNonConfigurationInstance ()
{
base.OnRetainNonConfigurationInstance ();
return _textView;
}
Nesta seção, aprendemos a preservar dados de estado simples com o Bundle
e persistir tipos de dados mais complexos com OnRetainNonConfigurationInstance
.
Resumo
O ciclo de vida da atividade do Android fornece uma estrutura poderosa para o gerenciamento de estado de atividades em um aplicativo, mas pode ser complicado entender e implementar. Este capítulo introduziu os diferentes estados pelos quais uma atividade pode passar durante seu tempo de vida, bem como os métodos de ciclo de vida associados a esses estados. Em seguida, foram fornecidas diretrizes sobre que tipo de lógica deve ser executada em cada um desses métodos.