💻 Exemplos: Capítulo 12: Injeção de Dependências com Koin e Hilt
Exemplos de Código: Capítulo 12 — Injeção de Dependências no Android
Especialização em Mobile Nativo com Android • Demonstrações Práticas Compiláveis
💻 Código de Demonstração: Arquitetura com DI Limpa usando Koin e Padrões Hilt
O código abaixo demonstra a orquestração e injeção de dependências corporativa no Android:
- Desacoplamento estrito entre contratos de interface (
IRepository) e implementações concretas. - Definição de escopos: Singletons (uma única instância na aplicação), Factory (novas instâncias) e ViewModel.
- Configuração idiomática com Koin DSL (
module { singleOf(); viewModelOf() }) e anotações comparativas do Hilt / Dagger.
package br.com.portal.mobile.android.cap12
// =====================================================================
// 1. Contratos de Domínio e Implementações
// =====================================================================
interface IClienteRepository {
fun buscarNomeCliente(id: String): String
}
class ClienteRepositoryRemoto : IClienteRepository {
override fun buscarNomeCliente(id: String): String {
return "Empresa Alfa Tecnologia (ID: $id)"
}
}
interface IServicoAuditoria {
fun registrarEvento(evento: String)
}
class ServicoAuditoriaConsole : IServicoAuditoria {
override fun registrarEvento(evento: String) {
println("[AUDITORIA DI] $evento")
}
}
// =====================================================================
// 2. ViewModel com Injeção por Construtor (Constructor Injection)
// =====================================================================
class ClienteDetalhesViewModel(
private val repository: IClienteRepository,
private val auditoria: IServicoAuditoria
) {
fun carregarDados(id: String): String {
auditoria.registrarEvento("Consultando cliente: $id")
return repository.buscarNomeCliente(id)
}
}
// =====================================================================
// 3. Configuração de Módulos Koin (Kotlin DSL Leve)
// =====================================================================
/*
import org.koin.core.module.dsl.singleOf
import org.koin.core.module.dsl.viewModelOf
import org.koin.dsl.bind
import org.koin.dsl.module
val moduloAppKoin = module {
// Registra Singleton: Compartilhado em toda a vida útil do App
singleOf(::ClienteRepositoryRemoto) bind IClienteRepository::class
// Registra Factory: Cria nova instância a cada solicitação
factory { ServicoAuditoriaConsole() } bind IServicoAuditoria::class
// Registra ViewModel: Ciclo de vida atrelado ao Navigation BackStack/Activity
viewModelOf(::ClienteDetalhesViewModel)
}
*/
// =====================================================================
// 4. Equivalente em Hilt / Dagger (Anotações em Tempo de Compilação)
// =====================================================================
/*
@Module
@InstallIn(SingletonComponent::class)
abstract class ModuloHiltRepositorios {
@Binds
@Singleton
abstract fun bindClienteRepository(
impl: ClienteRepositoryRemoto
): IClienteRepository
@Binds
abstract fun bindAuditoriaService(
impl: ServicoAuditoriaConsole
): IServicoAuditoria
}
@HiltViewModel
class ClienteDetalhesHiltViewModel @Inject constructor(
private val repository: IClienteRepository,
private val auditoria: IServicoAuditoria
) : ViewModel() {
// ...
}
*/
// =====================================================================
// 5. Container Manual Demonstrativo (Simulador do Motor de DI)
// =====================================================================
class MiniDIContainer {
private val singletons = mutableMapOf<Class<*>, Any>()
fun <T : Any> registrarSingleton(classe: Class<T>, instancia: T) {
singletons[classe] = instancia
}
@Suppress("UNCHECKED_CAST")
fun <T : Any> resolver(classe: Class<T>): T {
return singletons[classe] as? T
?: throw IllegalStateException("Dependência não registrada: ${classe.simpleName}")
}
}
fun main() {
println("=== INJEÇÃO DE DEPENDÊNCIAS: KOIN & HILT ARCHITECTURE ===")
val container = MiniDIContainer()
// Setup do Contêiner
container.registrarSingleton(IClienteRepository::class.java, ClienteRepositoryRemoto())
container.registrarSingleton(IServicoAuditoria::class.java, ServicoAuditoriaConsole())
// Resolução e instanciação limpa sem 'new' acoplado
val repo = container.resolver(IClienteRepository::class.java)
val audit = container.resolver(IServicoAuditoria::class.java)
val viewModel = ClienteDetalhesViewModel(repo, audit)
val resultado = viewModel.carregarDados("CLI-9988")
println("Resultado da Consulta no ViewModel: $resultado")
}