Por que eu devo ler este artigo:

Saber trabalhar com tarefas em paralelo na plataforma Android é essencial. Este artigo será útil no entendimento em relação à forma como tarefas paralelas devem ser executadas em uma aplicação Android a fim de evitar os erros conhecidos como ANR (Application Not Responding). Para exemplificar, será desenvolvida uma aplicação de consumo de feeds, a qual fará o download das mesmas a partir de um web service.

As aplicações para smartphones geralmente necessitam buscar recursos de fontes externas para realizar determinadas tarefas ou dar acesso ao usuário a algum conteúdo pertinente do escopo do aplicativo. Por se tratar de programação sequencial conforme mostra a Figura 1, quando a tarefa a ser realizada é custosa em relação ao tempo a ser gasto para realizá-la e o processamento desses recursos ocorre na UIThread conforme mostra a Figura 2, a aplicação é travada até que a instrução seja concluída. Por causa desse travamento, o sistema operacional fecha a aplicação evidenciando uma ANR (Application Not Responding), pois por restrição do próprio sistema operacional, nesse caso Android, o aplicativo não deve ficar mais do que cinco segundos indisponível às interações do usuário.

Para que tal erro não ocorra, é necessário utilizar formas de processamento em paralelo como Threads e tomar o cuidado de evitar a comunicação direta entre qualquer Thread que não seja a principal com a interface do usuário (UI).

Além de evitar o travamento pela indisponibilidade da aplicação em responder às interações do usuário, a programação em paralelo, de forma geral, também pode melhorar o desempenho da aplicação através da divisão a tarefa em partes menores a fim de tornar mais rápida a solução do problema.

Como ponto negativo, programar em paralelo é muitas vezes mais complicado além de trazer para o escopo novos problemas que não ocorrem na programação sequencial como a possibilidade de um método ser executado sem que ainda possua os valores corretos, os quais serão calculados em outro método.

Programação sequencial
Figura 1. Programação sequencial
Tarefas na UIThread
Figura 2. Tarefas na UIThread

Contudo, com o objetivo de fornecer ao usuário uma melhor experiência de uso, as instruções mais complexas e/ou demoradas da aplicação como, por exemplo, as requisições para serviços web, o acesso a um banco de dados ou arquivo, devem ser realizadas de forma concorrente para que a aplicação não fique indisponível.

Utilizando Thread

Thread é a forma de um processo se dividir sozinho em duas ou mais tarefas que podem ser executadas ao mesmo tempo de forma concorrente com seu estado variando entre: unstarted, running, suspended e stopped.

A vantagem de se utilizar Thread na aplicação é poder executar mais de uma tarefa ao mesmo tempo, evitando que a aplicação trave à espera de um processo demorado. No caso do sistema Android, essa demora, como já citado anteriormente, irá causar a finalização automática da aplicação enviando um erro ANR. Para executar tanto uma Thread quanto um Runnable, é necessário instanciar um objeto. No caso da classe Thread, para iniciar a execução, basta chamar o método start(), enquanto para a interface Runnable, o método run().

O sistema Android oferece o suporte para a utilização da classe Thread em Java para a realização de tarefas assíncronas, assim como do pacote java.util.concurrent para realização de tarefas em background. Contudo, o desenvolvedor deve ter certo cuidado ao utilizar uma classe que herde diretamente da classe Thread ou implemente a interface Runnable. Isso porque as mesmas não oferecem um recurso padrão para tratar as mudanças de configuração da aplicação como, por exemplo, a mudança do modo de orientação de retrato para paisagem ou vice-versa. A utilização da classe Thread também não oferece um recurso padrão para sincronização com a main thread (UIThread) em casos nos quais é necessário retornar um resultado. Além de todas essas implicações, a inexistência de um processo padrão para cancelamento da classe Thread faz com que a aplicação mantenha a classe executando até que esta termine mesmo que já não seja necessário que todo o processo nela seja executado.

Utilizando Handler

Para solucionar as limitações e suprir as desvantagens geradas para utilização da classe Thread em Java no próprio sistema, o Google desenvolveu a classe Handler, a qual está disponível desde a API level 1. Ela permite enviar e processar objetos da classe Message e da interface Runnable que estão associados a uma fila de mensagens/processos implementada pela classe MessageQueue.

A principal dificuldade encontrada pelos desenvolvedores ao criar processos em uma classe Thread ou Runnable é encontrar formas de enviar dados necessários entre as Threads. Para solucionar esse problema, um objeto da classe Handler oferece um canal único de comunicação com a Thread na qual o mesmo é instanciado. Outro ponto positivo da classe Handler é a possibilidade de reutilizar o objeto da classe Handler já existente em uma Activity e evitar assim que muitas instâncias sejam criadas.

Apesar de não possuir uma forma de implementação tão intuitiva, a classe Handler é comumente utilizada em casos no qual é necessário agendar a execução de objetos da classe Message ou Runnable. Outro caso no qual a classe Handler é utilizada é quando existe a necessidade de adicionar uma ação a uma fila de execução que não é a mesma da classe Handler. Para utilizá-la, é necessário criar uma classe que herde de Handler e que sobrescreva o método handleMessage(). Caso seja necessário agendar a execução de alguma tarefa para ser executada posteriormente, é possível fazer isso através de diversos métodos como post(), postDelayed(), sendMessage(), etc.

Utilizando AsyncTask

A fim de facilitar e possibilitar a utilização da UI Thread a partir de um processo em background, a classe AsyncTask foi disponibilizada a partir da API level 3. Com ela é possível processar, a partir do encapsulamento da criação e da sincronização com a UI Thread, as operações em background e retornar o resultado para a UI Thread sem a necessidade de manipular Threads e/ou Handlers. A classe AsyncTask é definida a partir de três parâmetros genéricos Params, Progress e Result, e quatro métodos onPreExecute(), doInBackground(), onProgressUpdate() e onPostResult().

A classe AsyncTask foi projetada para facilitar o desenvolvimento de tarefas simples (com duração de poucos segundos, no máximo) processadas em background. Além disso, ela possibilita informar o progresso da tarefa que está sendo executada e enviar o resultado obtido, quando existir, para a UI Thread de forma simples.

Contudo, assim como a Thread em Java, a AsyncTask não possui um método padrão para lidar automaticamente com alterações na aplicação como a mudança de orientação retrato para paisagem e vice-versa. Ou seja, caso a Activity na qual a AsyncTask está associada seja recriada, o desenvolvedor deve lidar com essa condição de forma manual. Uma solução comum é utilizar a AsyncTask associada a um Fragmen ...

Quer ler esse conteúdo completo? Seja um assinante e descubra as vantagens.
  • 473 Cursos
  • 10K Artigos
  • 100 DevCasts
  • 30 Projetos
  • 80 Guias
Tenha acesso completo