Concrete Logo
Hamburger button

Dagger 2, um ano depois

  • Blog
  • 17 de Agosto de 2016
Share

*Este post foi originalmente publicado no Medium pessoal do autor. Confira aqui.

Bibliotecas que ajudam a organizar melhor o código que produzimos são sempre bem-vindas, e já faz mais de um ano que comecei a estudar o Dagger 2.

Se você nunca mexeu com Dagger 2, talvez valha a pena dar uma olhada em alguns materiais antes de começar a ler este post. Um bom começo é a apresentação que fiz no TDC SP 2015, que aborda o assunto desde o início e traz várias referências relevantes no final 🙂

Cerca de 15 meses após o lançamento de sua primeira versão estável, como a biblioteca evoluiu? O que tem de novo nesse meio tempo até a versão 2.5lançada no mês passado?

@Reusable

Na versão 2.0 do Dagger já tínhamos um escopo padrão, o @Singleton, herdado da especificação JSR 330 para objetos que deveriam possuir apenas uma única instância ao longo de toda a aplicação. Na versão 2.3 do Dagger temos a introdução da anotação de escopo @Reusable, que nos fornece uma instância ativa de cada vez, podendo ou não ser reutilizada. Porém, ao contrário do @Singleton, não há garantia desse reuso. Esta anotação é interessante, por exemplo, para classes Helper ou Utils, ou qualquer outro tipo de classe stateless.

A utilização do @Reusable é feita no próprio método anotado com @Provides:

@Binds

Quem foi early adopter do Dagger 2 lembra que, quando queríamos trabalhar com interfaces e, ao mesmo tempo, separar a complexidade de criação de alguns objetos (interface e sua classe concreta, por exemplo), nossos módulos não ficavam exatamente elegantes. Até então, tínhamos que fazer algumas coisas como:

A partir da versão 2.4 temos a anotação @Binds, que permite que tenhamos módulos abstratos, nos quais fazemos apenas o bind da implementação e da abstração. Assim, podemos separar melhor a implementação dos módulos, além de possibilitar que o próprio Dagger otimize esse processo, conforme sugere a documentação.

Multibinding

Apesar de existir de forma mais primitiva na versão 2.0, a possibilidade de fazer multibindings e devolver objetos na forma de coleções (sejam elas em Map ou Set) evoluiu muito nas releases seguintes. A própria documentação ilustra diversos cenários e usos para essa funcionalidade.

Para realizar multibindings com Sets, basta anotar os métodos @Provides com @IntoSet (caso o método esteja adicionando apenas um valor à coleção), ou @ElementsIntoSet (caso o método esteja adicionando mais de um valor à coleção).

A implementação de uma Activity ficaria assim:

Para Maps, o método também deve ser anotado com @IntKey, @StringKey ou @ClassKey para que a dependência seja inserida corretamente e possa ser acessada pelo objeto injetado.

E a classe a ser injetada:

Caso determinado multibinding possa ser uma coleção vazia, é necessário criar um módulo abstrato e criar um método declarando tal coleção, anotando-o com @Multibinds:

Tem um artigo bem interessante sobre multibindings do Miroslaw Stanek, no qual ele utiliza Dagger, multibindings e Auto Factory para criar uma prova de conceito e injetar diferentes ViewHolders. Vale a leitura!

Producers

Também presente na versão 2.0, mas tendo evoluído e otimizado consideravelmente desde a primeira versão, os Producers são uma forma de injeção de dependências assíncrona.

Porém, nesse caso, temos as desvantagens de adicionar a dependência do Guava (o que pode aumentar consideravelmente a quantidade de métodos no APK, caso o Proguard não esteja sendo utilizado) e a verbosidade da solução, que não se baseia na especificação JSR 330.

Para o uso dos Producers, primeiramente temos que adicionar a dependência específica no nosso arquivo build.gradle:

Em seguida, precisamos criar um módulo que indique como as dependências assíncronas serão entregues, retornando um objeto Executor:

As nossas dependências (a serem entregues de forma assíncrona) devem ser declaradas em um @ProducerModule, muito similar aos módulos já utilizados. Já os métodos devem ser anotados com @Produces — por padrão, todas as dependências são singleton.

O componente precisa ser um @ProductionComponent, incluindo o módulo de execução e os Producer Modules. As dependências que serão injetadas são declaradas em métodos retornando um ListenableFuture, assim como no exemplo:

Os Production Components podem depender de componentes e módulos convencionais.

Por fim, uma das formas de se obter a dependência é por meio do método Futures.addCallback() do Guava:

Novamente, o artigo do Stanek ilustra o uso para os Producers mais a fundo, indicados para dependências pesadas e custosas — o que, teoricamente, deve ser evitado em um aplicativo Android 🙂

Conclusão

Posso dizer que a evolução do Dagger tem acontecido de forma bastante satisfatória, principalmente com um ciclo de releases mais constantes desde o início deste ano. Além disso, se antes havia algum receio do uso da biblioteca, posso dizer que alguns projetos em produção já rodam tranquilamente há meses sem quaisquer problemas relacionados ao uso dela.

Então, façam bom uso e viva o open source! 🙂 Ficou alguma dúvida ou tem algo a complementar? Aproveite os campos abaixo. Até a próxima!