Na maioria dos casos, cada aplicativo para Android é executado no próprio processo do Linux. Esse processo é criado para o app quando parte do código precisa ser executada e permanecerá em execução até que não seja mais necessário e o sistema precise reivindicar a memória para uso por outros apps.
Uma característica incomum e fundamental do Android é que o ciclo de vida do processo de um app não é diretamente controlado pelo próprio app. Em vez disso, ele é determinado pelo sistema por meio de uma combinação das partes do app que o sistema sabe que estão sendo executadas, da importância delas para o usuário e da quantidade de memória disponível no sistema.
É importante que os desenvolvedores de apps entendam como componentes de aplicativo diferentes (em especial Activity
, Service
e BroadcastReceiver
) afetam o ciclo de vida do processo do app. Não usar esses componentes corretamente pode fazer com que o sistema elimine o processo do app enquanto ele estiver fazendo um trabalho importante.
Um exemplo comum de um bug do ciclo de vida do processo é um BroadcastReceiver
que inicia uma linha de execução quando recebe um intent no método BroadcastReceiver.onReceive()
e depois retorna a partir da função. Uma vez retornado, o sistema considera que o BroadcastReceiver não está mais ativo e, assim, o processo de hospedagem dele não é mais necessário, a menos que outros componentes do aplicativo estejam ativos nele. Assim, o sistema pode eliminar o processo a qualquer momento para recuperar a memória e, ao fazer isso, encerrar a linha de execução gerada no processo. A solução para esse problema normalmente é programar um JobService
a partir do BroadcastReceiver para que o sistema saiba que ainda há trabalho ativo sendo feito no processo.
Para determinar quais processos precisam ser eliminados quando a memória estiver baixa, o Android coloca cada processo em uma "hierarquia de importância" baseada nos componentes executados neles e no estado desses componentes. Esses tipos de processo são, em ordem de importância:
- Um processo em primeiro plano é aquele que é necessário para o que o usuário está fazendo no momento. Vários componentes de aplicativo podem fazer com que o processo que o contém seja considerado em primeiro plano de maneiras diferentes. Um processo é considerado em primeiro plano se atender alguma das seguintes condições:
- Ele está executando um
Activity
na parte superior da tela com a qual o usuário está interagindo. O métodoonResume()
foi chamado. - Ele tem um
BroadcastReceiver
que está sendo executado no momento. O métodoBroadcastReceiver.onReceive()
está em execução. - Ele tem um
Service
que está executando o código em um dos callbacks (Service.onCreate()
,Service.onStart()
ouService.onDestroy()
).
- Ele está executando um
- Um processo visível está realizando uma tarefa da qual o usuário está ciente, então encerrá-lo causaria um impacto negativo significativo na experiência do usuário. Um processo é considerado visível nas seguintes condições:
- Ele está executando um
Activity
visível para o usuário na tela, mas não em primeiro plano. O métodoonPause()
foi chamado. Isso pode ocorrer, por exemplo, se a atividade em primeiro plano for exibida como uma caixa de diálogo que permite que a atividade anterior seja vista por trás dela. - Ele tem um
Service
em execução como um serviço em primeiro plano por meio deService.startForeground()
, que está pedindo que o sistema trate o serviço como algo de que o usuário está ciente ou que algo esteja essencialmente visível. - Ele hospeda um serviço que o sistema está usando para um recurso específico do qual o usuário está ciente, como um plano de fundo interativo, serviço de método de entrada etc.
O número desses processos em execução no sistema é menos limitado que os processos em primeiro plano, mas ainda relativamente controlado. Esses processos são considerados extremamente importantes e não serão eliminados, a menos que isso seja necessário para manter todos os processos em primeiro plano em execução.
- Ele está executando um
- Um processo de serviço é aquele que contém um
Service
que foi iniciado com o métodostartService()
. Embora esses processos não estejam diretamente visíveis para o usuário, eles geralmente fazem coisas com as quais o usuário se importa, como upload ou download de dados de rede em segundo plano. Assim, o sistema sempre mantém esses processos em execução, a menos que não haja memória suficiente para reter todos os processos em primeiro plano e visíveis.Os serviços que estão em execução há muito tempo, como 30 minutos ou mais, podem ter a importância rebaixada para permitir que o processo seja enviado para a lista de LRUs em cache descrita a seguir. Isso ajuda a evitar situações em que serviços de longa duração com vazamentos de memória ou outros problemas consumam muita memória RAM, impedindo o sistema de fazer um uso eficiente de processos em cache.
- Um processo armazenado em cache é um que não é necessário no momento. Portanto, o sistema está livre para eliminá-lo conforme desejado quando a memória for necessária em outro lugar. Em um sistema com comportamento normal, esses são os únicos processos envolvidos no gerenciamento de memória: um sistema bem executado terá vários processos em cache sempre disponíveis, para alternar entre apps de modo mais eficiente, e eliminará com frequência os mais antigos, conforme necessário.
Somente em situações muito críticas e indesejadas, o sistema chegará a um ponto em que todos os processos em cache serão eliminados e começará a eliminar processos de serviço.
Esses processos geralmente contêm uma ou mais instâncias
Activity
que não estão visíveis no momento para o usuário. O métodoonStop()
foi chamado e retornado. Desde que implementem o ciclo de vida da atividade corretamente (consulteActivity
para ver mais detalhes), quando o sistema eliminar esses processos, a experiência do usuário não será afetada ao retornar para o app. Ele poderá restaurar o estado salvo anteriormente quando a atividade associada for recriada em um novo processo.Esses processos são mantidos em uma lista de pseudo-LRU, em que o último processo na lista é o primeiro a ser eliminado para recuperar a memória. A política exata de ordenação nessa lista é um detalhe de implementação da plataforma, mas geralmente tentará manter processos mais úteis (aquele que hospeda o app de início do usuário, a última atividade que ele viu etc.) antes de outros tipos de processos. Outras políticas para eliminar processos também podem ser aplicadas: limites rígidos no número de processos permitidos, limites no tempo que um processo pode permanecer continuamente armazenado em cache etc.
Só haverá alguns desses processos no sistema, e eles só serão eliminados como um último recurso se a memória estiver tão baixa que nem mesmo esses processos possam continuar em execução. Geralmente, nesse ponto, o dispositivo atingiu um estado de paginação de memória, então essa ação é necessária para manter a interface do usuário responsiva.
Ao decidir como classificar um processo, o sistema baseará a decisão no nível mais importante encontrado entre todos os componentes ativos no processo.
Consulte a documentação Activity
, Service
e BroadcastReceiver
para ver mais detalhes sobre como cada um desses componentes contribui para o ciclo de vida geral de um processo.
A documentação de cada uma dessas classes descreve mais detalhadamente como elas afetam o ciclo de vida geral do app.
A prioridade de um processo também pode ser aumentada com base em outras dependências de um outro processo a ele. Por exemplo, se o processo A estiver vinculado a Service
com a sinalização Context.BIND_AUTO_CREATE
ou estiver usando um ContentProvider
no processo B, a classificação do processo B será sempre ao menos tão importante quanto a do processo A.