Hilt Series: Architecture Components com Dagger Hilt — ViewModel

Aprenda como injetar o ViewModel utilizando o Dagger Hilt no seu projeto

Ramon Ribeiro Rabello
Aug 4 · 5 min read
Image for post
Image for post
Photo by Jed Wood on Unsplash

Esse é o segundo artigo da Hilt Series, que é composta de várias partes:

Parte 1: Introdução ao Dagger Hilt

Parte 3: Migrando do Dagger para o Hilt (em breve)

Parte 4: Testes com Hilt (em breve)


Nesta segunda parte, será demonstrado um breve histórico sobre Architecture Components, comparativo de como injetar ViewModel com Dagger e como o Hilt pode ser facilmente integrado ao Architecture Components. Esse artigo irá focar apenas no ViewModel, por questão de escopo. A integração com outros componentes, como o Room, serão demonstrados no próximo artigo.

Relembrando: Architecture Components

Durante o I/O 2017, foi anunciado o Architecture Components, um conjunto de bibliotecas e guidelines criada pela Google para definição da arquitetura de projetos Android mais modernos, que englobava desde persistência, paginação, etc. Dentre os componentes lançados, o ViewModel foi uma das grandes sensações, pois, juntamente com o LiveData e Lifecycles, trouxe a tão aclamada solução para umas das maiores dores no desenvolvimento Android: , mesmo que inicialmente de forma incompleta.

Injetando ViewModel com Dagger

Logo que Architecture Components foi lançado, uma das dúvidas era como injetar o ViewModel em um projeto gerenciado e modularizado usando Dagger. Infelizmente, a injeção de um ViewModel com o Dagger ainda é disparadamente a que mais exige boilerplate, tanto que foi necessário um artigo dedicado para exemplificar todas as possíveis abordagens — e nenhuma delas é trivial.

Diante dessas várias abordagens, a que ficou mais popular foi a injeção por meio de multibindings, uma feature do Dagger 2 que permite realizar o , mesmo que estejam sendo providos em módulos diferentes. Para isso, a anotação @IntoMap era utilizada juntamente com @Binds para prover os ViewModels de acordo com uma chave, geralmente representada por uma anotação customizada, como @ViewModelKey.

Além disso, era necessário fornecer uma ViewModelProvider.Factory que seria responsável para realizar a construção dos ViewModels, como mostra o código a seguir.

Apesar da complexidade do código acima, o que essa factory faz é disponibilizar um ViewModel a partir de viewModelsMap, de acordo com o tipo da classe informada para a anotação @ViewModelKey.

Depois disso, será preciso criar outro Module que irá prover uma ViewModelFactory, da seguinte maneira:

Agora, basta vincular a ViewModelFactoryModule ao componente de escopo de aplicação, comumente denominado de ApplicationComponent nos projetos com Dagger:

Por fim, basta adicionar @Inject à declaração da ViewModelProvider.Factory:

Ou de forma bem concisa por meio da extension function viewModels(), disponível na biblioteca activity-ktx ou fragment-ktx:

E se esses passos pudessem ser simplificados? È aí que o Dagger Hilt entra em cena para deixar as coisas muito mais simples e produtivas, como vamos ver a seguir.

Injetando ViewModel com Dagger Hilt

Basicamente, o Hilt simplifica a injeção do ViewModel em . Mas antes, precisamos adicionar no arquivo build.gradle da aplicação a bibliteca de integração do Hilt com Lifecycle e ViewModel e depois fazer o sync do Gradle para baixar as dependências:

Depois, adicione a anotação @ViewModelInject no construtor do ViewModel:

No código acima, ao adicionar a anotação @ViewModelInject, o Hilt irá automaticamente realizar a injeção do ViewModel em qualquer Android Entry Point, como Activity ou Fragment. A anotação @Assisted é opcional e serve para indicar uma “injeção assistida”, isto é, o SavedStateHandle será injetado em tempo de execução utilizando uma AssistedFactory, porém esse parâmetro não fará parte do grafo de dependência.

Por fim, declare o ViewModel dentro de um @AndroidEntryPoint:

Qual a mágica que o Hilt faz para injetar o ViewModel?

Você notou que para realizar a injeção do ViewModel com o Hilt, não foi necessário criar mais nenhum Module ou Factory ou Annotation? Mas qual a mágica por trás de tudo isso?

Quando o Hilt identifica a anotação @ViewModelInject no construtor de um ViewModel, ele automaticamente gera todas as factories e modules necessários para realizar a injeção de dependência. O código abaixo é da classe LoggingViewModel_HiltModule gerada pelo Hilt para prover um ViewModelAssistedFactory. Ela fica localizada na pasta .

Observe a utilização das anotações @Binds, @IntoMap e @StringKey, algo semelhante como o ViewModelBindingModule foi definido usando Dagger 2. Um outro ponto importante para ressaltar é a utilização da anotação @InstallIn(ActivityRetainedComponent.class).

Como foi apresentado na parte 1 desta série, o Hilt define uma hierarquia de componentes por padrão, onde cada componente possui um escopo exclusivo. O componente ActivityRetainedComponent é utilizado quando é necessário injetar um comportamento que deva perdurar, mesmo se houver mudança de configuração, que no caso, é característica do ViewModel.

Outro código disponibilizado pelo Hilt interessante de mencionar é o HiltViewModelFactory, que foi simplificado por questão do escopo deste artigo.

Essa Factory já contém toda a complexidade de fornecimento de um ViewModel parametrizado com um SavedStateHandle, para fins de persistir o estado mesmo depois de mudança de configuração.

Conclusão

Esse artigo apresentou um breve histórico sobre Architecture Components, mostrou a complexidade em torno da injeção de ViewModel utilizando Dagger e como que o Hilt simplifica esse processo todo por meio da utilização da anotação @ViewModelInject para geração automática dos modules e factories necessárias para realizar a injeção de dependência do ViewModel. Na parte 3 desta série, será apresentado passo-a-passo como migrar do Dagger 2 para Hilt. Todo o código utilizado neste artigo, está disponível neste repositório no GitHub, no branch arch-viewmodel-inject.

Links

Android Dev BR

Artigos em português sobre Android, curados pela comunidade…

Ramon Ribeiro Rabello

Written by

Father, Speaker, Android Engineer & Tech Mentor @ Involves & Star Wars fan!

Android Dev BR

Artigos em português sobre Android, curados pela comunidade Android Dev BR. Junte-se a nós: https://androiddevbr.org/.

Ramon Ribeiro Rabello

Written by

Father, Speaker, Android Engineer & Tech Mentor @ Involves & Star Wars fan!

Android Dev BR

Artigos em português sobre Android, curados pela comunidade Android Dev BR. Junte-se a nós: https://androiddevbr.org/.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store