0

ViewModel com injeção de dependência

#Kotlin #Android
Francisco Rasia
Francisco Rasia

Que tal deixar seus ViewModels ainda mais poderosos e funcionais passando objetos por meio do construtor? Quem está familiarizado com o Android Jetpack sabe que o Viewmodel é um de seus principais elementos e um dos vértices do tripé MVVM (Model-View-ViewModel).

Nesse framework a Activity ou o Fragment ficam responsáveis somente pelos elementos visuais da interface, enquanto as regras de negócio e a lógica são responsabilidade do ViewModel.


💉Certo... mas por que injetar dependências?

Usar o ViewModel é uma prática recomendada pela Google, pois atende ao princípio da separação de responsabilidades. Mas, às vezes, temos necessidade de acessar outros componentes à partir do ViewModel, como, por exemplo, um repositório ou uma interface de banco de dados.

Nesses momentos acabamos tendo que instanciar o objeto dentro do ViewModel, o que pode levar a situações como a criação de múltiplas instâncias do mesmo objeto.

Outras vezes desejamos ter acesso a um objeto dependente do contexto da Activity, e, como está talhado no mármore do templo dos deuses do Android:


Não armazenarás referências ao contexto no ViewModel.


É aí que a injeção de dependências fica interessante. Por meio dessa ferramenta, podemos passar, via construtor, uma referência a um objeto qualquer, até mesmo um objeto que depende do contexto, sem ter receio de vazamento de memória*. E uma vez que temos a referência ao objeto, temos acesso aos seus métodos diretamente, sem que seja necessário instanciá-lo novamente.


*Isso é possível porque a referência ao contexto fica no objeto, e não no ViewModel.


🐱‍👤O truque ninja


É necessário criar uma ViewModelFactory personalizada para injetar uma dependência, i.e., passar um objeto como parâmetro do ViewModel.


1. Criar uma classe AlgumaCoisaViewModel

Essa classe deve herdar de ViewModel e receber um objeto como parâmetro:


class AlgumaCoisaViewModel(private val outraCoisa: OutraCoisa) : ViewModel() {
    //corpo do ViewModel
    }


2. Criar uma classe AlgumaCoisaViewModelFactory

Essa classe deve implementar a interface ViewModelProvider.Factory. Passar novamente o objeto como parâmetro do construtor dessa classe:


class AlgumaCoisaViewModelFactory(private val outraCoisa: OutraCoisa) : ViewModelProvider.Factory {

    }


3. Implementar o membro `create()` da interface

O compilador vai reclamar e pedir que você implemente os membros da interface - na verdade, é uma única função `create()`, que retorna um objeto genérico do tipo ViewModel. Implemente esse método, indicando que deseja retornar um objeto do tipo AlgumaCoisaViewModel, passando a dependência como parâmetro e fazendo o cast para o genérico T.

Ficou um pouco confuso, eu sei. Mas vai ficar mais claro no exemplo de código:


class AlgumaCoisaViewModelFactory(private val outraCoisa: OutraCoisa) : ViewModelProvider.Factory {

    @Suppress("UNCHECKED_CAST") // pode suprimir o alerta sem medo!
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return FilmListViewModel(outraCoisa) as T
    }
}


Sua Factory está pronta!


4. Instanciar a factory

De volta à Activity ou Fragment, instancie a Factory antes de chamar o ViewModelProvider, passando a dependência no construtor da Factory:


val outraCoisa = OutraCoisa() //nossa dependência
val factory = AlgumaCoisaViewModelFactory(outraCoisa)


5. Obter o ViewModel a partir da Factory criada

Chamar o ViewModelProvider, passando o dono do ViewModel (atividade ou fragmento) e a factory criada, além da classe do ViewModel esperado:


val outraCoisa = OutraCoisa()
val factory = AlgumaCoisaViewModelFactory(outraCoisa)

val mViewModel = ViewModelProvider(this, factory).get(AlgumaCoisaViewModel::class.java)


Parabéns! Você acaba de criar um ViewModel com dependências!


🚀​ Um exemplo prático

Vou utilizar como exemplo o projeto The Ghibli Lib. Você pode baixar o projeto no meu repositório ou seguir o passo-a-passo em qualquer projeto seu que ViewModel.


💻 Repositório no github: 💻 Repositório no github: https://github.com/chicorasia/bootcamp-libghi

Use o commit dc8e30b e a branch `content-provider` .


Confira o passo-a-passo no vídeo: 💊 Pílula de Kotlin - Viewmodel com injeção de dependência via Factory no Android com Kotlin - https://youtu.be/biFrt-Bjx-g


🎯 Conclusão

Nesse artigo nós vimos como injetar dependências no ViewModel por meio da Factory customizada, extendendo a interface ViewModelProvider.Factory. Essa é uma maneira simples, embora um pouco verbosa, de se obter ViewModels com acesso a outros objetos, até mesmo objetos que dependem do context.

Há outras maneiras de se fazer essa injeção de dependências - por exemplo, usando o Koin - mas esse é o tema do próximo artigo.


📸

Photo by Dennis Klicker on Unsplash

0
4

Comentários (1)

0
Isaias Bueno

Isaias Bueno

15/05/2021 20:59

O Koin foi o que eu mais utilizei para injeção de dependência nos meus testes/projetos, vou pesquisar mais sobre a sua ideia, incrível artigo!

Arquiteto, urbanista, desenvolvedor Java & Android e criador em chefe na chicorialabs.com.br

Brasil