NULL on error flipping bits whilst updating pixels

Turbinando o carregamento de imagens remotas no Android

Android

Recentemente, precisei fazer um fine tuning de carregamento de imagens num app.

O cenário era o seguinte: O app consiste em uma série de cardviews com imagens de background oriundos de diversos locais da internet, resultando em alguns problemas:

  • Resolver DNS para cada domínio
  • Handshake SSL para cada domínio
  • Algumas imagens são infinitamente maiores do que o necessário
  • Formatos diferentes (JPEG, PNG, GIF, WEBP, etc)
  • Latência alta ou mesmo instabilidade
  • O fato das imagens serem bem grandes, que imposibilita o OkHttp de fazer cache
  • Alto uso de memória
  • Não é legal fazer Inline linking

Somando todos esses fatores, a experiência do usuário é prejudicada pela baixa performance.

Resolvi então usar o thumbor como proxy. O thumbor é um projeto open-source mantido pela Globo, que permite aplicar diversos efeitos, cortes, ajustes e filtros em imagens, tudo configurável pela URL.

Exemplo http://thumbor.thumborize.me/unsafe/300x100/filters:rotate(90)/placehold.it/250x150/ff0000

Existe um recurso que usa visão computacional para identificar rostos numa foto e no momento de recortar não cortar nenhum pescoço e/ou enquadrar todas as pessoas.

Com o thumbor eu posso redimensionar a imagem para o tamanho exato que cada dispositivo vai precisar, converter para outro formato menor, remover todas as informações ICC embutidas no arquivo, além de outros filtros disponíveis.

Deploy do thumbor

O deploy do thumbor é bem simples; existem imagens do Docker prontas para serem usadas, buildpacks do Heroku, Elastic Beanstalk ou mesmo manual. Optei por usar o OpsWorks com o Chef, na verdade já existia até um cookbook do thumbor pronto para ser usado.

Content Delivery Network (CDN)

Aproveitei e criei uma CDN usando o CloudFront, assim as respostas do thumbor seriam cacheadas e distribuídas por todo os “points of presence (PoPs)”.

Pollexor

No Android temos uma biblioteca chamada pollexor, que permite escrever a URI do thumbor de uma maneira elegante usando fluent interface. Como já fazia uso do picasso para o carregamento de imagens, usei o picasso-pollexor, que funciona como um RequestTransformer para o Picasso, adicionando alguns parâmetros extras na URL de modo que a imagem seja recortada e enquadrada no tamanho exato do ImageView.

Thumbor thumbor = Thumbor.create(BuildConfig.THUMBOR_URL, BuildConfig.THUMBOR_KEY);
final RequestTransformer transformer =
    new PollexorRequestTransformer(thumbor);

Picasso picasso = new Picasso.Builder(context)
    .requestTransformer(transformer)
    .downloader(new OkHttp3Downloader(httpClient))
    .build();

Desta forma, o uso do Picasso em conjunto com o thumbor fica totalmente transparente para o programador. Ao informar o tamanho da imagem e o tipo de crop, o PollexorRequestTransformer entra em ação alterando os parâmetros da URL, de forma totalmente transparente. Prático, não? :)

@Bind(R.id.background)
ImageView background;

...

picasso.load(url)
  .fit()
  .centerCrop()
  .into(background);

Com isso, resolvemos uma série de problemas:

  • Será executado apenas um handshake de SSL
  • Apenas um domínio a ser consultado no DNS
  • A imagem é servida no tamanho exato que será exibida
  • A latência é muito menor devido a CDN
  • Possibilidade cachear em disco ou memória devido ao tamanho reduzido da imagem

Resultado

Normal Otimizado
image image

Já acabou, Jéssica?

O próximo passo é descobrir o sentido em que o usuário está rolando a lista e ir fazendo pre-fetch de algumas imagens, passando a impressão de carregamento instantâneo.