Dagger é um framework de injeção de dependência para Java e Kotlin que gera código DI em tempo de compilação através do processamento de anotações. Hilt é uma camada sobre o Dagger para Android que simplifica a configuração de componentes e o gerenciamento do ciclo de vida. De acordo com Google, 2025, o Hilt é usado em mais de 70% dos aplicativos Android do Top-100 do Google Play, suportando Activity, Fragment, ViewModel e Service através de componentes predefinidos. Ambos os frameworks fornecem verificação do grafo de dependências em tempo de compilação, eliminando erros de injeção em tempo de execução.
Principais pontos
Dagger é um framework de injeção de dependência com geração de código em tempo de compilação. Originalmente desenvolvido no Square e depois transferido para o Google, o Dagger usa o processador de anotações Java APT para analisar o grafo de dependências e gerar classes factory. Ao contrário de DI em tempo de execução (Guice, Koin), o Dagger não usa reflexão — todo o código é criado na compilação, garantindo máximo desempenho em tempo de execução e detecção de erros em tempo de build.
Hilt é uma biblioteca do Google construída sobre o Dagger e otimizada para Android. O Hilt fornece componentes predefinidos correspondentes ao ciclo de vida dos componentes Android: @SingletonComponent para Application, @ActivityComponent para Activity, @FragmentComponent para Fragment, @ViewModelComponent para ViewModel. Isso elimina a configuração rotineira de Component e Module necessária no Dagger puro. O Hilt também gera o grafo de dependências para cada componente Android automaticamente via @AndroidEntryPoint.
De acordo com o Google I/O 2024, o Hilt é a solução recomendada para DI em aplicativos Android escritos em Kotlin. As bibliotecas Jetpack (Navigation, Room, WorkManager) têm integração embutida com o Hilt via @HiltViewModel e @HiltWorker. Em projetos que não usam Android (bibliotecas Java/Kotlin puras, aplicações servidoras), usa-se o Dagger puro sem a camada do Hilt.
Sem um framework DI, o desenvolvedor cria objetos manualmente através de construtores ou fábricas, passando dependências ao longo da cadeia. Cada novo requisito significa alterar as assinaturas de todos os construtores na cadeia. Dagger automatiza esse processo: basta declarar qual tipo é necessário (@Inject constructor), e o Dagger cria o grafo de dependências, resolvendo todos os tipos aninhados. Quando as dependências mudam, o Dagger atualiza o código gerado automaticamente — é impossível errar na cadeia.
Injeção de dependência é um padrão no qual um objeto recebe suas dependências de fora em vez de criá-las por si mesmo. DI implementa o princípio de Inversão de Controle (IoC): uma classe não é responsável por criar suas próprias dependências, mas as declara através de um construtor, método ou campo. A injeção por construtor é considerada a mais preferível porque garante que o objeto seja criado em um estado válido.
| Tipo de injeção | Sintaxe do Dagger | Quando usar |
|---|---|---|
| Constructor injection | @Inject constructor | Método principal — para todas as classes próprias |
| Field injection | @Inject lateinit var | Apenas para componentes Android (Activity, Fragment) |
| Method injection | @Inject fun bind() | Para inicialização pós-construção |
As principais vantagens do DI incluem testabilidade (as dependências podem ser substituídas por objetos mock), baixo acoplamento (classes dependem de interfaces, não de implementações) e gerenciamento explícito do ciclo de vida de objetos através de scopes. Dagger garante automaticamente que um objeto seja criado uma vez dentro de seu escopo e destruído ao sair do escopo.
Component é o elemento central do grafo de dependências do Dagger. É uma interface anotada com @Component que descreve a ponte entre Module e os alvos de injeção. O Dagger gera a implementação do Component (por exemplo, DaggerAppComponent) em tempo de compilação. O Component determina quais tipos estão disponíveis para injeção através de métodos abstratos que retornam os tipos necessários ou através de métodos inject que aceitam um objeto para field injection.
// Module: fornece dependências que o Dagger não pode criar sozinho
@Module
class NetworkModule {
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build()
}
@Provides
@Singleton
fun provideApiService(client: OkHttpClient): ApiService {
return Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
}
// Component: conecta Module e alvos de Injection
@Component(modules = [NetworkModule::class])
interface AppComponent {
fun inject(activity: MainActivity)
fun getApiService(): ApiService
}
@Module é uma classe contendo métodos com @Provides que retornam instâncias de dependências. Module é usado para tipos que o Dagger não pode criar automaticamente: bibliotecas de terceiros (OkHttp, Retrofit), objetos com parâmetros de construtor, interfaces com seleção de implementação. @Binds é uma alternativa ao @Provides para casos em que um método retorna uma interface e aceita uma única implementação: o Dagger gera um cast direto sem chamar o método.
@Scope define o tempo de vida de um objeto no grafo de dependências. @Singleton — o objeto é criado uma vez para toda a aplicação. @ActivityScoped — o objeto vive enquanto a Activity viver. @FragmentScoped — enquanto o Fragment viver. Sem escopo, o Dagger cria uma nova instância a cada injeção. @Reusable — um escopo para objetos que não precisam ser singletons mas cuja criação é cara — o Dagger pode armazenar a instância em cache mas não garante isso.
Hilt simplifica a configuração do Dagger para Android através de componentes predefinidos e geração automática do grafo base. A anotação @HiltAndroidApp na classe Application aciona a geração do componente Hilt. Sem esta anotação, o Hilt não funciona — é obrigatória para qualquer aplicativo Android que use Hilt. @HiltAndroidApp cria o componente pai SingletonComponent, do qual todos os outros componentes da aplicação herdam.
@HiltAndroidApp
class MyApplication : Application()
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var apiService: ApiService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// apiService já injetado antes da chamada onCreate
}
}
@Module
@InstallIn(SingletonComponent::class)
class AppModule {
@Provides
@Singleton
fun provideDatabase(@ApplicationContext ctx: Context): AppDatabase {
return Room.databaseBuilder(ctx, AppDatabase::class.java, "app.db").build()
}
}
@AndroidEntryPoint é uma anotação para Activity, Fragment, Service, BroadcastReceiver e View. Ela gera um componente Hilt para cada tipo: @AndroidEntryPoint em uma Activity cria um ActivityComponent que herda de SingletonComponent. O componente filho recebe automaticamente todas as dependências do pai. Field injection com @Inject lateinit var está disponível apenas em classes anotadas com @AndroidEntryPoint — em classes normais, usa-se constructor injection.
@InstallIn especifica em qual componente Hilt um módulo é instalado. NetworkModule com @InstallIn(SingletonComponent::class) está disponível em toda a aplicação. Um Module com @InstallIn(ActivityComponent::class) está disponível apenas na Activity. Isso isola os grafos de dependência: módulos específicos de Activity não são visíveis em Fragment e ViewModel, prevenindo o uso acidental de dependências inválidas. @ApplicationContext é um qualificador embutido do Hilt para obter o Context da aplicação.
Quando duas implementações diferentes da mesma interface precisam ser injetadas, usam-se qualificadores. O Hilt suporta @Named para identificadores de string e anotações personalizadas com @Qualifier. Por exemplo, @Named("baseUrl") e @Named("imageBaseUrl") para diferentes configurações de string. Qualificadores personalizados são preferíveis ao @Named devido à verificação em tempo de compilação — um nome de string incorreto não será detectado até o tempo de execução.
@HiltViewModel é uma anotação que substitui a fábrica manual ViewModelProvider.Factory. Uma classe anotada com @HiltViewModel com @Inject constructor recebe automaticamente todas as dependências através do Dagger. O Hilt gera uma ViewModelFactory usada pelo Jetpack ViewModelProvider. Sem o Hilt, o desenvolvedor precisa escrever a fábrica manualmente, passando cada parâmetro da Activity ou fragmento.
@HiltViewModel
class MainViewModel
@Inject constructor(
private val apiService: ApiService,
private val database: AppDatabase
) : ViewModel() {
private val _users = MutableStateFlow<List<User>>(emptyList())
val users: StateFlow<List<User>> = _users.asStateFlow()
fun loadUsers() {
viewModelScope.launch {
_users.value = apiService.getUsers()
}
}
}
// Na Activity — Hilt cria automaticamente o ViewModel
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
}
ViewModelScoped é um escopo do Hilt para dependências que vivem enquanto o ViewModel viver. Se dois ViewModels do mesmo tipo injetam a mesma dependência @ViewModelScoped, cada um recebe sua própria instância. Isso distingue @ViewModelScoped de @ActivityScoped, onde uma Activity recebe uma instância para todos os fragmentos. Para dependências específicas de ViewModel (por exemplo, SavedStateHandle), usa-se @HiltViewModel com @Inject constructor(savedStateHandle: SavedStateHandle).
O Hilt suporta assisted injection através da biblioteca Hilt Extensions. A injeção assistida permite passar parâmetros ao construtor no momento da injeção quando algumas dependências só são conhecidas em tempo de execução (por exemplo, o ID do usuário de uma intent). Para assisted injection, usa-se @AssistedInject em combinação com parâmetros @Assisted. O Hilt gera uma AssistedFactory que pode ser injetada da forma padrão.
Dagger puro requer a criação manual de Component, definição de escopos e configuração da injeção em cada componente Android. O desenvolvedor cria AppComponent, ActivityComponent, FragmentComponent e gerencia seus relacionamentos através de @Subcomponent. Esta abordagem dá máximo controle mas requer uma quantidade significativa de código boilerplate. O Dagger é usado em projetos grandes que exigem uma arquitetura DI não padrão, ou em projetos Java/Kotlin não Android.
Hilt automatiza o boilerplate: um @HiltAndroidApp, um @AndroidEntryPoint para cada componente, escopos predefinidos. O Google recomenda o Hilt para todos os novos projetos Android. A migração do Dagger para o Hilt inclui substituir Component por @InstallIn, substituir @Subcomponent por componentes Hilt predefinidos e substituir a fábrica manual ViewModelProvider.Factory por @HiltViewModel. A maioria das classes @Module é migrada com a adição de @InstallIn sem alterar os métodos @Provides.
| Característica | Dagger | Hilt |
|---|---|---|
| Configuração | Manual: Component, Subcomponent, Builder | Automática: @HiltAndroidApp, @AndroidEntryPoint |
| Componentes Android | Sem predefinição | 12+ componentes integrados |
| ViewModel | Fábrica manual | @HiltViewModel + @Inject constructor |
| Multimódulo | Via @Component(dependencies) | Via @InstallIn + agregação |
| Complexidade | Alta — experiência necessária | Baixa — intuitivamente compreensível |
| Flexibilidade | Máxima | Padrão (cobre 95% dos cenários) |
Limitações do Hilt: a biblioteca só suporta Android (não adequada para projetos Java puramente servidores), impõe uma certa estrutura de componentes (difícil de sobrescrever) e adiciona uma dependência ao android.hilt:hilt-navigation-compose para projetos Jetpack Compose. Para aplicações Compose, o Hilt fornece @HiltViewModel acessível em Composable através de hiltViewModel() — sem necessidade de fornecer ViewModel manualmente a partir da Activity.
Perguntas frequentes
Dagger é um framework DI básico em tempo de compilação com configuração manual de Component e Module. Hilt é uma camada para Android que automatiza a criação de componentes e a integração com o ciclo de vida de Activity, Fragment, ViewModel, Service e BroadcastReceiver.
@HiltAndroidApp ativa a geração do componente Hilt para Application. Sem esta anotação, o Hilt não pode criar o SingletonComponent base do qual todos os ActivityComponent, FragmentComponent e ViewModelComponent herdam. A anotação é obrigatória para qualquer projeto Hilt.
Hilt Navigation fornece @HiltViewModel para ViewModel em NavBackStackEntry e hiltNavGraphViewModels() para escopar ViewModel dentro do grafo de navegação. A biblioteca android.hilt:hilt-navigation-fragment cria automaticamente um ViewModel para cada NavBackStackEntry.
Use @ApplicationContext para o contexto da aplicação ou @ActivityContext para o contexto da Activity. O Hilt fornece esses qualificadores embutidos na biblioteca android.hilt:hilt-android. @ActivityContext está disponível apenas em módulos instalados no ActivityComponent.
@Binds é uma alternativa eficiente ao @Provides quando um método aceita exatamente um parâmetro e retorna seu tipo como interface. @Binds gera um cast direto sem chamar o método, reduzindo a quantidade de código gerado e melhorando o desempenho da injeção.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também