Neste tutorial iremos explorar o paralelismo de processamento no Android. Para isso, será feita uma série de posts explicando as possibilidades de processamento paralelo e como cada uma pode ser utilizada.
Quando uma aplicação é iniciada, o sistema cria uma Thread para o aplicativo, chamada de “main”. Essa thread é muito importante, pois é responsável por despachar eventos para os widgets de interface de usuário, incluindo eventos de desenho. Também é a thread na qual o aplicativo interage com os componentes do framework UI Android (componentes como android.widget e android.view). Como tal, essa thread também é chamada de UI Thread.
Por padrão, todos os componentes do mesmo aplicativo são executados no mesmo processo e thread. Se um componente da aplicação começa e já existe um processo para essa aplicação (porque outro componente da aplicação existe), então o componente é iniciado dentro desse processo e usa a mesma thread de execução.
O sistema não cria uma thread separada para cada instância de um componente. Todos os componentes que são executados no mesmo processo são uma instancia do UI Thread, e chamadas de sistema para cada componente são emitidas dessa thread. Consequentemente, os métodos que respondem a chamadas de retorno do sistema (como onKeyDown () para informar as ações do usuário ou um método de retorno de chamada do ciclo de vida) são sempre executados UI Thread UI do processo.
Na Figura 1, podemos ver cada um dos elementos presentes em uma aplicação Android. Cada máquina virtual Dalvik executa dentro de um processo Linux. Das possíveis threads que a aplicação pode trabalhar, temos a UI Thread, responsável pelos componentes Android com visualização do usuário e a Background Thread, BG, que efetua o processamento em lote, independente da interface. Os objetos java são na verdade componentes com ciclo de vida que geridos pelo sistema Android. Cada ciclo de vida é associado as demandas de recurso do equipamento, como memória disponível, interação com o usuário e processamento.
Figura 1 – Raio-x da aplicação Android
O ciclo de vida básico das threads, de UI e BG podem ser vistas na Figura 2.
Figura 2- Ciclo de Vida das Threads na execução de uma aplicação Android
Como mencionado, cada componente tem um ciclo de vida, descrito pela sua interação com o sistema e o usuário. O componente que possui ciclo de vida mais dinâmico é a atividade, Activity, sendo este a “unidade molecular” de uma aplicação Android. A relação entre as instâncias dos objetos Activity e o componente que possui o ciclo de vida pode ser mostrado pela relação com as threads que são associadas ao mesmo. A Figura 3 esquematiza essa relação entre os componentes. Os métodos OnCreate() e OnDestroy() são chamados pelo sistema no momento que o objeto é criado. Mesmo diferentes instâncias podem ser associadas ao mesmo componente, devido aos estados esperados durante seu ciclo de vida. Dessa maneira, apesar de ser transparente para o programador, o mesmo deve conhecer em qual estado o componente se encontra para conseguir manipular suas instâncias.
Figura 3. Ciclo de vida do componente Activity
Por padrão, todos os componentes do mesmo aplicativo são executados no mesmo processo e a maioria dos aplicativos não devem mudar isso. No entanto, se você achar que precisa controlar quais processos que um determinado componente pertence, você pode fazê-lo no arquivo de Manifest. A entrada no arquivo Manifest para cada tipo de componente “element” – <activity>, <serviço>, <receiver>, e <provider> -suporta um “android:process:” que pode especificar um processono qual esse componente deve ser executado. Você pode definir esse atributo para que cada componente. Você também pode definir android:process para que componentes de diferentes aplicativos sejam executados no mesmo processo que os aplicativos compartilham o mesmo ID de usuário Linux e são assinados com os mesmos certificados fornecidos pelo processo. O <application> também suporta um android:process , para definir um valor padrão que se aplica a todos os componentes.
O Android pode decidir encerrar um processo em algum momento, quando houver pouca memória, e processos que estão servindo ao usuário demandar por mais espaço. Componentes de aplicativos em execução no processo que for morto são consequentemente destruídos. Um processo é iniciado novamente para os componentes quando há novamente alguma demanda para que eles. Ao decidir quais processos matar, o sistema Android pesa sua importância relativa para o usuário. Por exemplo, irá encerrar um processo cujos componentes Activity não são mais visíveis na tela, em comparação a um processo que tem componentes visíveis. A decisão de terminar um processo, por conseguinte, depende do estado dos componentes que funcionam no processo.
Hierarquia de Processos no Android
O sistema Android tenta manter um processo de aplicativo o máximo de tempo possível, mas, eventualmente, precisa remover processos antigos para recuperar memória para processos novos ou mais importantes. Para determinar quais processos a manter e quais matar, o sistema coloca cada processo em uma “hierarquia de importância” com base nos componentes em execução no processo e o estado desses componentes. Processos com o menor importância são eliminadas em primeiro lugar, em seguida, aqueles com a seguinte menor importância, e assim por diante, como necessários para recuperar recursos do sistema. Existem cinco níveis na hierarquia de importância:
- Foreground process
- Visible process
- Service process
- Background process
- Empty process
Android classifica um processo no nível mais alto que pode, com base na importância dos componentes atualmente ativos no processo. Por exemplo, se um processo hospeda um serviço e uma atividade visível, o processo é classificado como um processo visível, e não um processo de serviço. Além disso, a classificação de um processo pode ser aumentada porque outros processos são dependentes dela, um processo que está servindo outro processo nunca pode ser classificada em posição inferior do que o processo que está servindo. Por exemplo, se um fornecedor de conteúdos no processo A é um cliente do serviço em que o processo B, ou se um serviço no processo A está ligado a um componente de processo B, processo A é sempre considerada pelo menos tão importante como o processo B. A seguir o detalhamento de cada classificação:
Foreground Process
Processo o qual o usuário está interagindo no momento. Um processo é considerado como em primeiro plano, se qualquer uma das condições que se seguem aconteça:
- possui uma Activity que o usuário está interagindo com (método onResume() da Activity foi chamado).
- possui um Service que está ligado àActivity que o usuário está interagindo.
- possui um Service que está sendo executado “em primeiro plano” -o serviço chamou startForeground ().
- possui um Service que está executando um dos seus retornos de chamada de ciclo de vida (onCreate (), onStart (), ou onDestroy ()).
- possui um BroadcastReceiver que está executando seu método OnReceive ().
Visible Process
Um processo que não tem nenhum componente de primeiro plano, mas ainda pode afetar o que o usuário vê na tela. Um processo é considerado visível se qualquer uma das seguintes condições:
- Hospeda uma Activity que não está em primeiro plano, mas ainda é visível para o usuário (seu método onPause () foi chamado). Isto pode ocorrer, por exemplo, quando a Activity do primeiro plano iniciado um diálogo, o que permite que a Activity anterior ser vista por trás dele.
- Hospeda um Service que está ligado a umaActivity visível.
Um processo visível é considerado extremamente importante e não será morto a menos que seja necessário para manter todos os Foreground process em execução.
Service Process
Um processo que está executando um serviço que foi iniciado com o método StartService () e não se enquadra em nenhuma das duas categorias mais elevadas.
Embora os processos de serviço não estão diretamente ligados a qualquer coisa que o usuário vê, eles são geralmente fazendo coisas que o usuário se preocupa (como a reprodução de música em segundo plano ou o download de dados na rede), de modo que o sistema mantém-los em execução, a menos que não há memória suficiente para retê-los, juntamente com todos os novos conhecimentos e processos visíveis.
Background Process
Um processo que possui uma atividade não disponível ao usuário (método onStop () foi chamado). Esses processos não têm impacto direto sobre a experiência do usuário, e o sistema pode matá-los a qualquer momento para recuperar memória para um processo de maior hierarquia. Normalmente, há muitos processos em segundo plano em execução, de modo que eles são mantidos em uma lista LRU (menos usado recentemente) para garantir que o processo com a atividade que foi visto mais recentemente pelo usuário é o último a ser morto. Se uma atividade implementa seus métodos de ciclo de vida corretamente, e salva seu estado atual, matar o seu processo não terá um efeito visível sobre a experiência do usuário, porque quando o usuário navega de volta para a atividade, a atividade restaura todo o seu estado visível.
Empty Process
Um processo que não detém quaisquer componentes de aplicativos ativos. A única razão para manter este tipo de processo vivo é para fins de armazenamento em cache , para melhorar o tempo de inicialização na próxima vez que um componente precisa ser executado na mesma. O sistema de mata frequentemente estes processos, a fim de equilibrar os recursos gerais do sistema entre caches de processo e os caches do kernel subjacentes.
Nos próximos posts iremos explorar qual a melhor maneira de delegar o processamento para as threads de background de acordo com as demandas da aplicação e os requisitos de processamento do Android.
Referencia:
[1]http://developer.android.com/guide/components/processes-and-threads.html
[2] http://developer.android.com/guide/topics/manifest/activity-element.html
One thought on “Tutorial Android – Paralelismo: Introdução”