Dagger / Hilt: qué es, DI y aplicación

Autor: IT Sectr Publicado: 2026-05-03 Tiempo de lectura: 9 min

Dagger es un framework de inyección de dependencias para Java y Kotlin que genera código DI en tiempo de compilación mediante el procesamiento de anotaciones. Hilt es una capa sobre Dagger para Android que simplifica la configuración de componentes y el ciclo de vida. Según Google, 2025, Hilt se usa en más del 70% de las aplicaciones Android del Top-100 de Google Play, soportando Activity, Fragment, ViewModel y Service a través de componentes predefinidos. Ambos frameworks proporcionan verificación del grafo de dependencias en tiempo de compilación, eliminando errores de inyección en tiempo de ejecución.

Puntos clave

  • Dagger — framework DI en tiempo de compilación con generación de código mediante anotaciones @Module, @Provides, @Component
  • Hilt — capa para Android que simplifica Dagger mediante @HiltAndroidApp, @AndroidEntryPoint, @HiltViewModel
  • Component — grafo de dependencias que conecta Module con objetivos Inject a través de métodos proxy
  • Scope — @Singleton, @ViewModelScoped, @ActivityScoped gestionan el tiempo de vida de los objetos inyectados
  • Hilt soporta proyectos multimódulo mediante @InstallIn para grafos de dependencias aislados

¿Qué es Dagger / Hilt?

Dagger es un framework de inyección de dependencias con generación de código en tiempo de compilación. Desarrollado originalmente en Square y luego transferido a Google, Dagger utiliza el procesador de anotaciones Java APT para analizar el grafo de dependencias y generar clases factory. A diferencia de DI en tiempo de ejecución (Guice, Koin), Dagger no usa reflexión — todo el código se crea en la compilación, garantizando el máximo rendimiento en tiempo de ejecución y detección de errores en la compilación.

Hilt es una biblioteca de Google construida sobre Dagger y optimizada para Android. Hilt proporciona componentes predefinidos correspondientes al ciclo de vida de los componentes Android: @SingletonComponent para Application, @ActivityComponent para Activity, @FragmentComponent para Fragment, @ViewModelComponent para ViewModel. Esto elimina la configuración rutinaria de Component y Module requerida en Dagger puro. Hilt también genera el grafo de dependencias para cada componente Android automáticamente mediante @AndroidEntryPoint.

Según Google I/O 2024, Hilt es la solución recomendada para DI en aplicaciones Android escritas en Kotlin. Las bibliotecas Jetpack (Navigation, Room, WorkManager) tienen integración incorporada con Hilt mediante @HiltViewModel y @HiltWorker. En proyectos que no usan Android (bibliotecas Java/Kotlin puras, aplicaciones de servidor), se usa Dagger puro sin la capa de Hilt.

El problema de la inyección manual de dependencias

Sin un framework DI, el desarrollador crea objetos manualmente mediante constructores o fábricas, pasando dependencias a lo largo de la cadena. Cada nuevo requisito implica cambiar las firmas de todos los constructores en la cadena. Dagger automatiza este proceso: solo hay que declarar qué tipo se necesita (@Inject constructor), y Dagger crea el grafo de dependencias, resolviendo todos los tipos anidados. Cuando las dependencias cambian, Dagger actualiza el código generado automáticamente — es imposible equivocarse en la cadena.

Principios de inyección de dependencias

Inyección de dependencias es un patrón en el que un objeto recibe sus dependencias desde el exterior en lugar de crearlas por sí mismo. DI implementa el principio de Inversión de Control (IoC): una clase no es responsable de crear sus propias dependencias, sino que las declara a través de un constructor, método o campo. La inyección por constructor se considera la más preferible porque garantiza que el objeto se crea en un estado válido.

Tipo de inyecciónSintaxis de DaggerCuándo usar
Constructor injection@Inject constructorMétodo principal — para todas las clases propias
Field injection@Inject lateinit varSolo para componentes Android (Activity, Fragment)
Method injection@Inject fun bind()Para inicialización post-construcción

Ventajas de DI en tiempo de compilación

Las principales ventajas de DI incluyen testabilidad (las dependencias se pueden reemplazar con objetos mock), bajo acoplamiento (las clases dependen de interfaces, no de implementaciones) y gestión explícita del ciclo de vida de los objetos mediante scopes. Dagger garantiza automáticamente que un objeto se crea una vez dentro de su scope y se destruye al salir del scope.

Arquitectura de Dagger: Component, Module, Provides

Component es el elemento central del grafo de dependencias de Dagger. Es una interfaz anotada con @Component que describe el puente entre Module y los objetivos de inyección. Dagger genera la implementación de Component (por ejemplo, DaggerAppComponent) en tiempo de compilación. El Component determina qué tipos están disponibles para inyección a través de métodos abstractos que devuelven los tipos requeridos o mediante métodos inject que aceptan un objeto para field injection.

kotlin
// Module: proporciona dependencias que Dagger no puede crear por sí mismo
@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 y los objetivos de Injection
@Component(modules = [NetworkModule::class])
interface AppComponent {
    fun inject(activity: MainActivity)
    fun getApiService(): ApiService
}

@Module es una clase que contiene métodos con @Provides que devuelven instancias de dependencias. Module se usa para tipos que Dagger no puede crear automáticamente: bibliotecas de terceros (OkHttp, Retrofit), objetos con parámetros de constructor, interfaces con selección de implementación. @Binds es una alternativa a @Provides para casos en que un método devuelve una interfaz y acepta una única implementación: Dagger genera un cast directo sin llamar al método.

@Scope define el tiempo de vida de un objeto en el grafo de dependencias. @Singleton — el objeto se crea una vez para toda la aplicación. @ActivityScoped — el objeto vive mientras vive la Activity. @FragmentScoped — mientras vive el Fragment. Sin scope, Dagger crea una nueva instancia en cada inyección. @Reusable — un scope para objetos que no tienen que ser singletons pero cuya creación es costosa — Dagger puede almacenar en caché la instancia pero no lo garantiza.

Hilt para Android: @HiltAndroidApp y @AndroidEntryPoint

Hilt simplifica la configuración de Dagger para Android mediante componentes predefinidos y generación automática del grafo base. La anotación @HiltAndroidApp en la clase Application desencadena la generación del componente Hilt. Sin esta anotación, Hilt no funciona — es obligatoria para cualquier aplicación Android que use Hilt. @HiltAndroidApp crea el componente padre SingletonComponent, del que heredan todos los demás componentes de la aplicación.

kotlin
@HiltAndroidApp
class MyApplication : Application()

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject lateinit var apiService: ApiService

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // apiService ya inyectado antes de la llamada a 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 es una anotación para Activity, Fragment, Service, BroadcastReceiver y View. Genera un componente Hilt para cada tipo: @AndroidEntryPoint en una Activity crea un ActivityComponent que hereda de SingletonComponent. El componente hijo recibe automáticamente todas las dependencias del padre. Field injection con @Inject lateinit var solo está disponible en clases anotadas con @AndroidEntryPoint — en clases normales se usa constructor injection.

@InstallIn especifica en qué componente Hilt se instala un módulo. NetworkModule con @InstallIn(SingletonComponent::class) está disponible en toda la aplicación. Un Module con @InstallIn(ActivityComponent::class) solo está disponible en Activity. Esto aísla los grafos de dependencias: los módulos específicos de Activity no son visibles en Fragment y ViewModel, evitando el uso accidental de dependencias no válidas. @ApplicationContext es un calificador incorporado de Hilt para obtener el Context de la aplicación.

Qualifier: @Named y calificadores personalizados

Cuando se necesitan inyectar dos implementaciones diferentes de la misma interfaz, se usan calificadores. Hilt soporta @Named para identificadores de cadena y anotaciones personalizadas con @Qualifier. Por ejemplo, @Named("baseUrl") y @Named("imageBaseUrl") para diferentes configuraciones de cadena. Los calificadores personalizados son preferibles a @Named debido a la verificación en tiempo de compilación — un nombre de cadena incorrecto no se detectará hasta tiempo de ejecución.

Hilt ViewModel: @HiltViewModel y @Inject constructor

@HiltViewModel es una anotación que reemplaza la fábrica manual ViewModelProvider.Factory. Una clase anotada con @HiltViewModel con @Inject constructor recibe automáticamente todas las dependencias a través de Dagger. Hilt genera una ViewModelFactory utilizada por Jetpack ViewModelProvider. Sin Hilt, el desarrollador debe escribir la fábrica manualmente, pasando cada parámetro desde la Activity o el fragmento.

kotlin
@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()
        }
    }
}

// En Activity — Hilt crea automáticamente el ViewModel
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    private val viewModel: MainViewModel by viewModels()
}

ViewModelScoped es un scope de Hilt para dependencias que viven mientras vive el ViewModel. Si dos ViewModels del mismo tipo inyectan la misma dependencia @ViewModelScoped, cada uno obtiene su propia instancia. Esto distingue @ViewModelScoped de @ActivityScoped, donde una Activity obtiene una instancia para todos los fragmentos. Para dependencias específicas de ViewModel (por ejemplo, SavedStateHandle), se usa @HiltViewModel con @Inject constructor(savedStateHandle: SavedStateHandle).

Hilt soporta assisted injection a través de la biblioteca Hilt Extensions. La inyección asistida permite pasar parámetros al constructor en el momento de la inyección cuando algunas dependencias solo se conocen en tiempo de ejecución (por ejemplo, el ID de usuario de un intent). Para assisted injection se usa @AssistedInject en combinación con parámetros @Assisted. Hilt genera una AssistedFactory que se puede inyectar de forma estándar.

Dagger vs Hilt: comparación y migración

Dagger puro requiere la creación manual de Component, la definición de scopes y la configuración de la inyección en cada componente Android. El desarrollador crea AppComponent, ActivityComponent, FragmentComponent y gestiona sus relaciones mediante @Subcomponent. Este enfoque da el máximo control pero requiere una cantidad significativa de código boilerplate. Dagger se usa en proyectos grandes que requieren una arquitectura DI no estándar, o en proyectos Java/Kotlin que no son Android.

Hilt automatiza el boilerplate: un @HiltAndroidApp, un @AndroidEntryPoint para cada componente, scopes predefinidos. Google recomienda Hilt para todos los proyectos nuevos de Android. La migración de Dagger a Hilt incluye reemplazar Component por @InstallIn, reemplazar @Subcomponent por componentes Hilt predefinidos y reemplazar la fábrica manual ViewModelProvider.Factory por @HiltViewModel. La mayoría de las clases @Module se migran con la adición de @InstallIn sin cambiar los métodos @Provides.

CaracterísticaDaggerHilt
ConfiguraciónManual: Component, Subcomponent, BuilderAuto: @HiltAndroidApp, @AndroidEntryPoint
Componentes AndroidSin predefinidos12+ componentes integrados
ViewModelFábrica manual@HiltViewModel + @Inject constructor
MultimóduloMediante @Component(dependencies)Mediante @InstallIn + agregación
ComplejidadAlta — se necesita experienciaBaja — intuitivamente comprensible
FlexibilidadMáximaEstándar (cubre el 95% de escenarios)

Limitaciones de Hilt: la biblioteca solo soporta Android (no es adecuada para proyectos Java puramente de servidor), impone una estructura de componentes determinada (difícil de sobrescribir) y añade una dependencia de android.hilt:hilt-navigation-compose para proyectos Jetpack Compose. Para aplicaciones Compose, Hilt proporciona @HiltViewModel accesible en Composable mediante hiltViewModel() — sin necesidad de proporcionar ViewModel manualmente desde Activity.

Preguntas frecuentes

¿Cuál es la diferencia entre Dagger y Hilt?

Dagger es un framework DI básico en tiempo de compilación con configuración manual de Component y Module. Hilt es una capa para Android que automatiza la creación de componentes y la integración con el ciclo de vida de Activity, Fragment, ViewModel, Service y BroadcastReceiver.

¿Por qué se necesita @HiltAndroidApp?

@HiltAndroidApp activa la generación del componente Hilt para Application. Sin esta anotación, Hilt no puede crear el SingletonComponent base del que heredan todos los ActivityComponent, FragmentComponent y ViewModelComponent. La anotación es obligatoria para cualquier proyecto Hilt.

¿Cómo funciona Hilt con Jetpack Navigation?

Hilt Navigation proporciona @HiltViewModel para ViewModel en NavBackStackEntry y hiltNavGraphViewModels() para el scoping de ViewModel dentro del grafo de navegación. La biblioteca android.hilt:hilt-navigation-fragment crea automáticamente un ViewModel para cada NavBackStackEntry.

¿Cómo inyectar Context en Hilt?

Use @ApplicationContext para el contexto de la aplicación o @ActivityContext para el contexto de Activity. Hilt proporciona estos calificadores incorporados en la biblioteca android.hilt:hilt-android. @ActivityContext solo está disponible en módulos instalados en ActivityComponent.

¿Qué es @Binds y cuándo usarlo?

@Binds es una alternativa eficiente a @Provides cuando un método acepta exactamente un parámetro y devuelve su tipo como interfaz. @Binds genera un cast directo sin llamar al método, reduciendo la cantidad de código generado y mejorando el rendimiento de la inyección.

Resumen

  • Dagger — framework DI en tiempo de compilación con anotaciones @Module, @Provides, @Component y generación de código mediante APT
  • Hilt — capa Android sobre Dagger con @HiltAndroidApp, @AndroidEntryPoint, @InstallIn y componentes predefinidos
  • Component gestiona el grafo de dependencias, Module proporciona clases de terceros, Provides proporciona fábricas de objetos
  • Scope (@Singleton, @ViewModelScoped, @ActivityScoped) define el tiempo de vida del objeto en el grafo de Dagger
  • @HiltViewModel automatiza la creación de ViewModel, eliminando las fábricas manuales ViewModelProvider.Factory
  • @InstallIn aísla módulos por componentes, evitando fugas de dependencias entre capas de la aplicación
  • Hilt es recomendado por Google para todos los proyectos nuevos de Android, Dagger para arquitecturas DI no Android y personalizadas

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también