Caso prefira, você encontrará todo esse material, em inglês, no site do Developer Android. A tradução e comentários dos materiais eu faço livremente para ajudar a comunidade que fala português.

segunda-feira, 21 de fevereiro de 2011

Ciclo de vida de uma aplicação Android

Visão geral de classe


Uma activity é uma tarefa, muito focada, do que um usuário pode fazer. Quase todas as atividades interagem com o usuário, então uma classe de atividade toma conta da criação de uma janela para você onde você poderá colocar todos os componentes de UI (User Interface) com o setContentView(view). Enquanto atividades são normalmente apresentadas para o usuário como telas full-screen, elas também podem ser apresentadas de outra maneira: como janelas flutuantes (através de um tema com windosIsFloating configurado) ou embutido dentro de outra atividade (usando ActivityGroup). Existem dois métodos que quase todas as subclasses de Activity vão implementar:

  • OnCreate(Bundle) é onde você inicializa sua atividade. Mais importante, aqui você vai usualmente chamar setContentView(int) com o recurso de layout definindo a sua interface, e usar findViewById(int) para retornar os widgets naquela interface que você que interagir programaticamente.
  • OnPause() é onde você lida com o usuário deixando a sua atividade. Mais importante, quaisquer mudanças feitas pelo usuário deverá, nesse ponto, ser efetivada (usualmente através do ContentProvider que guarda os seus dados).
Para que possa ser usado pelo Context.startActivity, todas as classes de atividade devem ter uma declaração <activity> no manifesto da sua aplicação em AndroidManifest.xml.

A classe Activity é a mais importante no ciclo de vida de uma aplicação e a forma como as atividades são lançadas e unidas é parte fundamental para a plataforma de modelo de aplicação. 

Ciclo de Vida

Atividades no sistema são gerenciadas como um activity stack, ou pilha de atividades em português. Quando uma atividade é iniciada, ela é colocada no topo da pilha e se torna a atividade corrente - a atividade anterior sempre permanece abaixo na pilha e não vai ser mostrada enquanto a atividade corrente não terminar.

Uma atividade tem quatro estados essenciais:

  • Se uma atividade está sendo executada e está sendo mostrada na tela (que é o topo da pilha), ela está em modo active ou running.
  • Se uma atividade perdeu o foco mas ainda assim está visível (ou seja, uma nova atividade está sendo mostrada na tela mas não ocupando-a completamente - atividades em janelas flutuantes, por exemplo, ela está em modo paused. Uma atividade em modo paused está completamente viva (ela mantém todos os estados e informações e mantém-se relacionada ao gerenciador de janelas), mas pode ser encerrado pelo sistema em situações de memória baixa extremas.
  • Se uma atividade é completamente obscurecida por outra atividade, ela está em modo stopped. Ela ainda retém o seu estado e informações, contudo não é mais visível pelo usuário e sua janela está escondida e pode acontecer de ser encerrada pelo sistema quando for necessário liberar memória.
  • Se uma atividade está em modo paused ou stopped, o sistema pode retirar a atividade da memória simplesmente pedindo a ela que seja finalizada ou simplesmente matando o seu processo. Quando é mostrada novamente ao usuário, ela terá de ser novamente reiniciada e restaurada para seu estado anterior.
O diagrama abaixo mostra os caminhos importantes de uma activity. Os retângulos representam chamadas a métodos que você pode implementar para realizar operações quando a atividade se mode entre os estados. Os retângulos com cantos arredondados são os estados principals que uma atividade pode ter.


Existem três laços que você pode achar interessante monitorar dentro de sua atividade:

  • O ciclo de vida completo de uma atividade acontece entre a primeira chamada do onCreate(Bundle) até o onDestroy(). Uma atividade vai fazer toda a configuração do estado "global" no onCreate() e liberar os recursos remanescentes em onDestroy(). Por exemplo, se você tem uma thread rodando em background para fazer o download de dados da rede, você deve criar essa thread em onCreate() e então pará-la em onDestroy().
  • O vida visível de uma atividade acontece entre o onStart até o onStop. Durante esse tempo o usuário pode ver a atividade na tela, apesar de às vezes não estar completamente visível ao usuário. Entre esses dois métodos você pode manter os recursos que são necessários para mostrar a atividade ao usuário. Por exemplo, você pode registrar um BroadcastReceiver no onStart() para monitorar as mudanças que impactam a interface. Os métodos onStart() e onStop() podem ser chamados múltiplas vezes enquanto a atividade se torna visível e escondida do usuário.
  • A vida na frente de tela de uma atividade (que é enquanto a atividade está visível completamente na tela do usuário), acontece entre onResume() até o onPause(). Durante esse tempo a atividade está na frente de outras atividades e interagindo com o usuário. Uma atividade pode frequentemente ir de status resumed para paused -- por exemplo, quando o smartphone ou dispositivo onde o app roda entrar em modo sleep - e por isso o código desses métodos deve ser mais simples.
O ciclo de vida de uma atividade é definida pelos métodos de atividade mostrados abaixo. Todos eles podem ser sobrescritos para fazer o trabalho apropriado quando um estado de atividade mude. Todas as atividades vão implementar onCreate(Bundle) para que as mudanças de dados sejam persistidas e, de outra maneira, preparar para encerrar a interação com o usuário. Voc}e pode sempre chamar a superclasse quando implementando um desses métodos.

 public class Activity extends ApplicationContext {

     protected void onCreate(Bundle savedInstanceState);
     protected void onStart();     
     protected void onRestart();
     protected void onResume();
     protected void onPause();
     protected void onStop();
     protected void onDestroy();

 }
 
Em geral, o movimento através do ciclo de vida das atividades se parece com o que vai abaixo:

MétodoDescriçãoPode ser morto?Próximo
onCreate()Chamado quando a atividade é criado. Aqui é quando você deve fazer todas as funções como: criar as views, linkar os dados às listas, etc. NãoonStart()
 onRestart()Chamado após a atividade ser parada e antes de ser reinciada. Sempre seguida por  onStart()NãoonStart()
onStart()Chamado quando a atividade se torna visível ao usuário. Seguido pelo onResume() se a atividade roda na frente ou por onStop() se ela se torna invisível.NãoonResume()ou onStop()
 onResume()Chamado quando a atividade vai iniciar a interação com o usuário. Nesse ponto, sua atividade está no topo da pilha de atividades e quaisquer dados que sejam inseridos serão feitos aqui. Sempre seguido pelo  onPause().NãoonPause()
onPause()Chamado quando o sistema está por resumir a atividade anterior. Isso é tipicamente usado para persistir quaisquer mudanças ainda não efetivadas, parar animações e oturas coisas que possam consumir a CPU, etc. Implementações desse método devem ser rápidos pois a próxima atividade não será mostrada até que esse método seja finalizado. Seguido por onResume() se a atividade retornar para a frente ou onStop() se ela se tornar invisível ao usuário.SimonResume()ou
onStop()
onStop()Chamado quando a atividade não mais estiver visível ao usuário, pois outra atividade foi resumida e está na frente desta. Isso pode acontecer porque outra atividade está sendo iniciada, uma atividade existende está sendo trazida para a frente ou essa atividade estiver sendo finalizada. Seguida pelo onRestart() se essa atividade está voltando para interagir com o usuário ou onDestroy() se a atividade estiver sendo encerrada.SimonRestart()ou
onDestroy()
onDestroy()A chamada final que você receberá antes que a atividade seja destruída ou finalizada. Isso pode acontecer porque a atividade está, de fato, sendo encerrada (alguém chamou finish() nela) ou porque o sistema está temporariamente destruindo a instância da atividade para aumentar o espaço na memória. Você pode distinguir entre esses cenários com o método isFinishing()Simnada

Note a coluna "pode ser morto". Para essas atividades que estão marcadas como tal, após o método retornar o processo que está sendo chamado, ela poderá ser morta pelo sistema em qualquer momento sem que outra linha de código precise ser executada. Por conta disso, é recomendável que seja usado o método onPause() para persistir dados em banco. Em adição a isso, o método onSaveInstanceState(Bundle) é chamado antes de colocar a atividade em background, permitindo que seja salvo quaisquer estados dinâmicos de instância de sua atividade, para que possa ser recuperada posteriormente em onCreate(Bundle), se a atividade precisar ser recriada. Note que é importante persistir dados no onPause ao invés do onSaveInstanceState(Bundle) já que   o método onSaveInstanceState não faz parte das chamadas do ciclo de vida e portanto não será chamada em todas as situações descritas na documentação.

Mudanças na configuração

Se a configuração de um dispositivo (como definido na classe Resources.Configuration) mudar, então qualquer coisa mostrando uma interface ao usuário deverá ser atualizada para ficar de acordo com as novas configurações. Já que a atividade é o mecanismo principal de interação com o usuário, ele inclui suporte especial para gerenciamento de mudanças de configurações.

A não ser que você especifique o contrário, uma mudança de configuração (como a mudança na orientação da tela, lingua, dispositivo de entrada - se teclado físico ou virtual, etc) vai causar a destruição da atividade corrente, indo através da atividade normal no ciclo de vida do processo em onPause(), onStop() e onDestroy(). Se a atividade está na tela do dispositivo, uma vez chamado o onDestroy(), a instância é destruída e uma nova instância da atividade é criada, com quaisquer estados que estavam na interface anterior restaurados na nova instância a partir do estado gerado pelo onSaveInstanceState(Bundle).

Isso é feito dessa maneira pois quaisquer recursos, sejam arquivos de layout, recursos de aplicação, etc, podem ser mudados baseados nos valores de configuração. Então, a única maneira segura de gerenciar uma mudança de configuração é retornar todos os recursos, incluindo layouts, imagens e strings. E já que as atividades já sabem como salvar seus estados e recriar-se a partir desses estados, essa é uma maneira conveniente de fazer com que a atividade seja reiniciada quando uma nova configuração é apresentada.

Salvando estados de persistência.

Existem dois tipos de persistência de estado que uma atividade por ter: dados compatilhados (tipicamente guardados em um banco de dados SQLite usando um content provider) e um estado interno como preferências de usuário.

Para dados de um content provider, sugerimos que as atividades usem um modelo de edição no local. Ou seja, quaisquer edições que o usuário faz são efetivados imediatamente no banco de dados sem requerer uma confirmação adicional. Suporte a esse modelo geralmente é simples e geralmente basta seguir as duas regras seguintes:

  • Quando criando um novo documento, a entrada do banco de dados, ou arquivo onde será gravado o dado, é criada automaticamente. Por exemplo, se um usuário escolhe escrever um novo email, uma nova entrada para o email é criado assim que ele começa a inserir dados. Assim, se ele for para outra atividade após esse ponto, o email aparecerá como rascunho.
  • Quando uma atividade está no método onPause(), ele deverá persistir para o banco de dados quando houve modificação de dados. Isso assegura que essas mudanças sejam vistas por quaisquer outras atividades que venham a ser executadas. Você vai, provavelmente, persistir seus dados mais agressivamente em momentos chaves durante o ciclo de vida da atividade: por exemplo, antes de iniciar uma atividade, antes de finalizar a sua atividade, quando o usuário alterna entre campos de entrada, etc.
Esse modelo foi feito para prevenir que dados sejam perdidos quando um usuário está navegando entre atividades e permite que o sistema faça a retirada segura de uma atividade da memória (pois recursos de sistema estão sendo requeridos em outro local) em qualquer momento quando ele estiver em modo onPause(). Note que isso implica que o usuário, ao pressionado o botão voltar na sua atividade não significa que ele esteja cancelando a atividade - isso apenas significa que ele está deixando a atividade e que seu estado corrente foi salvo de qualquer maneira. Cancelando a edição em uma atividade deve ser provido com algum outro tipo de mecanismo como um reverter explícito ou mesmo uma opção de desfazer.

Processo do ciclo de vida

O sistema Android tenta manter os processos de aplicações em memória pelo tempo máximo possível mas eventualmente será necessário remover processos antigos quando a memória começa a ficar menos disponível. A decisão de qual processo ser removido é intimamente ligado ao estado da interação do processo com o usuário. Em geral, existem quatro tipos de processos que podem ser baseados nas atividades que estão rodando, abaixo listadas em ordem de importância. O sistema vai matar processos menos importantes antes de matar processos mais importantes na tentativa de liberar memória.

  1. Atividade de frente (foreground activity) - A atividade que está sendo rodada naquele instante é considerada a mais importante. Seus processos somente serão mortos como último recurso, se ele usar mais memória que o que vem disponível no dispositivo. Geralmente nesse momento o dispositivo já chegou ao estado de uso de paginação, então é requerido matar esse processo será necessário para manter a resposta de interface.
  2. Atividade visível (visible activity) - Uma atividade que está visível mas o usuário não o têm na frente, como uma atividade que fica atrás de um diálogo em janela flutuante, por exemplo, é considerada extremamente importante e não será morta a não ser que seja requerido para que a atividade de frente possa continuar rodando.
  3. Atividade de fundo (background activity) - Uma atividade que não é visível ao usuário e que está em modo onPause() não é mais crítica e o sistema poderá, de maneira bastante segura, matar seu processo na memória para que possa ser usada por outros processos. Se esse processo precisar ser morto, quando o usuário navegar de volta a ele (fazendo com que ele se torne visível novamente na tela), o método onCreate(Bundle) dele será chamado com o savedInstanceState suprido pelo onSaveInstanceState(Bundle) para que possa ser reiniciado no mesmo estado que foi deixado.
  4. Processo vazio é um processo que não tem nenhuma atividade ou outros componentes de aplicação rodando nele (como um Service ou BroadcastReceiver). Eles são rapidamente mortos pelo sistema assim que é necessário mais memória. Então, quaisquer operações de fundo que precisam ser executadas fora da atividade devem ser executadas no contexto de uma atividade BroadcastReceiver ou Service para assegurar que o sistema saiba que é necessário mantê-la no ar para que seu processo seja executado.
Algumas vezes uma atividade necessita que uma operação que é longa seja executada independentemente do ciclo de vida da aplicação. Um exemplo é o de uma aplicação de câmera que esteja fazendo o upload de uma imagem para um site. O upload pode tomar bastante tempo e a aplicação deverá permitir ao usuário que ele saia dela sem que, no entanto, o upload pare. Para conseguir isso, sua atividade deverá iniciar um Service no qual o upload é feito. Isso permite ao sistema priorizar apropriadamente seu processo pela duração do upload, independentemente se a aplicação original está pausada, parada ou finalizada.

*traduzido livremente do site do Android

1 comentários:

laramaki disse...

Bom artigo, obrigado. Mas fica uma dúvida: na seção Processo do Ciclo de Vida, no item 3 (Atividade de fundo), não estaria a atividade em modo onStop(), ao invés de onPause()? Já que atividade está completamente em background.

Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.
Related Posts Plugin for WordPress, Blogger...