Arquivo mensal: maio 2015

Carregando imagens no Android

Lidar com imagens no Android pode ser uma dor de cabeça para programadores iniciantes, há muitos conceitos a serem aprendidos e certamente muitas surpresas no meio do caminho.

Quando comecei a exibir imagens nos meus apps logo percebi que obter o resource (tanto do SD card quanto da Web) é algo lento que normalmente faz o aplicativo ficar vários segundos travado, principalmente se forem muitas imagens. Isso me levou a pesquisar mais a respeito e descobri algo mágico: AsyncTasks!

AsyncTasks[0] permitem que você execute tarefas pesadas em uma thread separada e, quando ela for concluída, você pode fazer o que quiser com o resultado. Como o processamento é feito em background a thread principal fica livre e não causa as travadas que todo usuário odeia.

Eu achava que era mágico até encontrar outra multitude de problemas e depois de dias enfrentando problemas por utilizar AsyncTasks para carregar imagens concluí que esse recurso simplesmente não foi feito para este fim. Foi aí então que resolvi pesquisar como os desenvolvedores mais experientes fazem isso e encontrei duas bibliotecas realmente incríveis: Picasso[1] e o Glide[2].

Carregando uma imagem

Tanto o Picasso quanto o Glide são gratuitos e têm o código disponível para quem quiser dar uma olhada no GitHub. Mas o que elas têm de especial? Elas são extremamente simples de usar, olha só:

Picasso

Picasso.with(contexto).load("http://i.imgur.com/DvpvklR.png").into(imageView);

Glide

Glide.with(contexto).load("http://i.imgur.com/DvpvklR.png").into(imageView);

Em apenas uma linha de código tanto o Picasso quanto o Glide são capazes de carregar uma imagem e exibi-la em um imageView, permitindo que você não se preocupe com threads, AsyncTasks, etc.  Para a operação de carregamento de imagem os dois são idênticos, mas em operações mais complexas eles são diferentes.

Como parâmetros de carregamento podem ser utilizados:

Redimensionando uma imagem

Em quase todos os casos a imagem carregada não é do mesmo tamanho do imageView que a exibirá e é sua responsabilidade redimensionar a imagem – afinal, cada pixel ocupa preciosos kilobytes de memória e é sempre bom economizar. O Picasso e o Glide disponibilizam métodos simples de redimensionamento.

Picasso

Picasso.with(contexto).load("http://i.imgur.com/DvpvklR.png").resize(200,200).into(imageView);

Glide

Glide.with(contexto).load("http://i.imgur.com/DvpvklR.png").override(200,200).into(imageView);

Os métodos de redimensionamento recebem tamanhos em pixels. Neste momento o Glide e o Picasso se distinguem internamente:

O Picasso irá armazenar a imagem original em cache exibirá no imageView uma cópia redimensionada. Desta forma se futuramente você carregar a mesma imagem em um imageView de tamanho diferente o carregamento será muito mais rápido porque não será necessário recuperar a imagem do armazenamento novamente (de um servidor remoto, por exemplo).

Já o Glide não armazenará a imagem original em cache, ele irá redimensioná-la, carregá-la no ImageView e descartar a imagem original. Isso faz com que o Glide economize memória mas faz com que a imagem seja recuperada novamente caso vocẽ queira carregá-la com uma resolução diferente.

Usando placeholders

Um placeholder é um elemento simples exibido no lugar que será ocupado por outro – mais pesado – quando este terminar de carregar. É comum que requisições através da internet demorem alguns segundos para serem concluídas e é importante deixar o usuário ciente de que algo está acontecendo.

Existem dois tipos de placeholders:

  • Carregamento: São exibidos enquanto a imagem principal não é carregada, são importantes principalmente quando imagens são carregadas através da rede.
  • Erro: São exibidos quando o carregamento da imagem falha por algum motivo.

O Picasso e o Glide suportam o carregamento e remoção de placeholders de maneira automática, bastando defini-los durante o carregamento da imagem como demonstrado:

Picasso

Picasso.with(contexto)
.load("http://i.imgur.com/DvpvklR.png")
.resize(200,200)
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.into(imageView);

Glide

Glide.with(contexto)
.load("http://i.imgur.com/DvpvklR.png")
.override(200,200)
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.into(imageView);

Conclusão

Qual dos dois é o melhor? Não existe uma resposta definitiva basicamente porque em informática não existe o conceito de X é melhor que Y e sim que X é melhor que Y na situação Z. Em casos gerais tanto o Picasso quanto o Glide têm a mesma performance e consumo de memória semelhantes, já em situações específicas… experimente os dois pra descobrir qual se adéqua melhor às necessidades da sua aplicação.

Para saber mais

Se quiser se aprofundar mais sobre os assuntos tratados nesse artigo consulte as referências abaixo:

[0] AsyncTasks – Android Developers
https://developer.android.com/reference/android/os/AsyncTask.html

[1] Picasso – GitHub
https://github.com/square/picasso

[2] Glide – GitHub
https://github.com/bumptech/glide