Injeção de Dependência (Dependency Injection) em Kotlin: guia completo

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução à Injeção de Dependência em Kotlin



O desenvolvimento moderno em Kotlin requer um gerenciamento adequado de dependências entre classes. Dependency Injection (DI) é um padrão de projeto que permite passar as dependências de um objeto externamente, em vez de criá-las internamente. Isso reduz o acoplamento do código, simplifica os testes e torna a aplicação mais flexível.



Neste artigo, vamos entender o que é injeção de dependência, por que ela é necessária e explorar três abordagens para implementá-la em Kotlin: injeção manual, uso da biblioteca Hilt e do framework leve Koin. O material será útil tanto para iniciantes quanto para desenvolvedores experientes que desejam organizar a arquitetura de seus projetos.



Fundamentos da Injeção de Dependência



Problema sem DI



Imagine a classe UserService, que cria diretamente uma instância de UserRepository:



class UserService {    private val repository = UserRepository() // acoplamento rígido

fun getUser(id: Int): User { return repository.findById(id) }}


Esse código é difícil de testar: você não consegue substituir UserRepository por um objeto mock. Além disso, ao alterar o construtor de UserRepository, será necessário modificar todos os locais onde ele é criado.



Solução: injeção via construtor



A maneira mais simples de aplicar DI é passar a dependência pelo construtor:



class UserService(private val repository: UserRepository) {    fun getUser(id: Int): User {        return repository.findById(id)    }}


Agora, UserService não sabe como UserRepository é criado. Você pode passar qualquer implementação — um banco de dados real, uma camada falsa ou um mock para testes.



Inversão de Controle (IoC)



DI está intimamente ligado ao princípio Inversion of Control (IoC). Em vez de a classe controlar a criação de suas dependências, o controle é transferido para um contêiner externo ou fábrica. Isso torna o sistema com baixo acoplamento e facilmente extensível.



Injeção Manual de Dependências (Manual DI)



Para projetos pequenos ou fins educacionais, é possível dispensar frameworks. Vamos criar um contêiner de dependências simples manualmente.



Exemplo: contêiner de dependências



// Definindo a interface do repositóriointerface UserRepository {    fun findById(id: Int): User}

// Implementaçãoclass UserRepositoryImpl : UserRepository { override fun findById(id: Int): User { // lógica para obter usuário do banco de dados return User(id, "User$id") }}

// Contêiner que reúne todas as dependênciasclass AppContainer { val userRepository: UserRepository = UserRepositoryImpl() val userService: UserService by lazy { UserService(userRepository) }}

// Usofun main() { val container = AppContainer() val service = container.userService println(service.getUser(1))}


Vantagens: controle total, sem dependências externas, simplicidade de compreensão.

Desvantagens: à medida que o projeto cresce, o contêiner se expande, tornando difícil gerenciar o ciclo de vida dos objetos e seus escopos.



Injeção de Dependência com Hilt



Hilt é a biblioteca oficial do Google para DI em aplicativos Android com Kotlin. Ela é construída sobre o Dagger, mas é significativamente mais simples de configurar.



Configuração do Hilt



Adicione no build.gradle.kts (nível do projeto):



plugins {    id("com.google.dagger.hilt.android") version "2.48" apply false}


No build.gradle.kts do módulo do aplicativo:



plugins {    id("com.google.dagger.hilt.android")}

dependencies { implementation("com.google.dagger:hilt-android:2.48") kapt("com.google.dagger:hilt-compiler:2.48")}

Blogs

Book Recommendations