Dagger — јесте фрејмворк за убризгавање зависности за Java и Kotlin, који генерише DI код у фази компилације кроз обраду анотација. Hilt — јесте надградња над Dagger-ом за Android, која поједностављује подешавање компонената и животног циклуса. Према подацима Google, 2025, Hilt се користи у више од 70% Android апликација из Google Play Top-100, подржавајући Activity, Fragment, ViewModel и Service кроз предефинисане компоненте. Оба фрејмворка обезбеђују проверу графа зависности у време компилације, елиминишући грешке убризгавања у време извршавања.
Главне карактеристике
Dagger — јесте фрејмворк за убризгавање зависности са генерисањем кода у фази компилације (compile-time DI). Развијен у Square-у и касније предат Google-у, Dagger користи процесор анотација Java APT за анализу графа зависности и генерисање фабричких класа. За разлику од runtime-DI (Guice, Koin), Dagger не користи рефлексију — сав код се ствара при компилацији, што обезбеђује максималне перформансе у рантиме-у и откривање грешака у фази изградње.
Hilt — јесте библиотека од Google-а, изграђена на Dagger-у и оптимизована за Android. Hilt пружа предефинисане компоненте које одговарају животном циклусу Android компонената: @SingletonComponent за Application, @ActivityComponent за Activity, @FragmentComponent за Fragment, @ViewModelComponent за ViewModel. Ово елиминише рутинско подешавање Component и Module које је потребно у чистом Dagger-у. Hilt такође генерише граф зависности за сваку Android компоненту аутоматски кроз @AndroidEntryPoint.
Према Google I/O 2024, Hilt је препоручено решење за DI у Android апликацијама писаним у Kotlin-у. Jetpack библиотеке (Navigation, Room, WorkManager) имају уграђену интеграцију са Hilt-ом кроз @HiltViewModel и @HiltWorker. У пројектима који не користе Android (чисте Java/Kotlin библиотеке, серверске апликације), примењује се чист Dagger без Hilt надградње.
Без DI фрејмворка, програмер креира објекте ручно кроз конструкторе или фабрике, преносећи зависности дуж ланца. Сваки нови захтев — промена сигнатуре свих конструктора у ланцу. Dagger аутоматизује овај процес: довољно је декларисати који тип је потребан (@Inject constructor), и Dagger ће креирати граф зависности, решавајући све угнежђене типове. При промени зависности, Dagger аутоматски ажурира генерисани код — немогуће је погрешити у ланцу.
Убризгавање зависности (Dependency Injection) — јесте образац у којем објекат прима своје зависности споља, а не ствара их сам. DI имплементира принцип инверзије контроле (IoC): класа није одговорна за стварање својих зависности, већ их декларише кроз конструктор, метод или поље. Убризгавање кроз конструктор (constructor injection) сматра се најпожељнијим, јер гарантује да се објекат креира у валидном стању.
| Тип убризгавања | Синтакса Dagger-а | Када користити |
|---|---|---|
| Constructor injection | @Inject constructor | Главни начин — за све сопствене класе |
| Field injection | @Inject lateinit var | Само за Android компоненте (Activity, Fragment) |
| Method injection | @Inject fun bind() | За пост-конструкт иницијализацију |
Главне предности DI укључују тестирабилност (зависности се могу заменити mock објектима), слабу повезаност (класе зависе од интерфејса, а не имплементација) и експлицитно управљање животним циклусом објеката кроз scope-ове. Dagger аутоматски гарантује да се објекат креира једном у оквиру свог scope-а и уништава при изласку из scope-а.
Component — централни елемент графа зависности Dagger-а. То је интерфејс анотиран са @Component који описује мост између Module-а и циљева убризгавања. Dagger генерише имплементацију Component (нпр. DaggerAppComponent) у фази компилације. Component одређује који типови су доступни за убризгавање, кроз апстрактне методе које враћају потребне типове или кроз inject методе које примају објекат за field injection.
// Модул: обезбеђује зависности које Dagger не може сам креирати
@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)
}
}
// Компонента: повезује Module и циљеве убризгавања
@Component(modules = [NetworkModule::class])
interface AppComponent {
fun inject(activity: MainActivity)
fun getApiService(): ApiService
}
@Module — јесте класа која садржи методе са @Provides које враћају инстанце зависности. Module се користи за типове које Dagger не може аутоматски креирати: библиотеке трећих страна (OkHttp, Retrofit), објекти са параметрима конструктора, интерфејси са избором имплементације. @Binds — алтернатива за @Provides у случајевима када метод враћа интерфејс и прима једну имплементацију: Dagger генерише директан cast без позивања метода.
@Scope одређује животни век објекта у графу зависности. @Singleton — објекат се креира једном за целу апликацију. @ActivityScoped — објекат живи док живи Activity. @FragmentScoped — док живи Fragment. Без scope-а, Dagger креира нову инстанцу при сваком убризгавању. @Reusable — scope за објекте који не морају бити синглтони, али је њихово креирање скупо — Dagger може кеширати инстанцу, али то не гарантује.
Hilt поједностављује подешавање Dagger-а за Android захваљујући предефинисаним компонентама и аутоматском генерисању основног графа. Анотација @HiltAndroidApp на Application класи покреће генерисање Hilt компоненте. Без ове анотације Hilt не ради — обавезна је за сваку Android апликацију која користи Hilt. @HiltAndroidApp креира родитељску компоненту SingletonComponent, од које наслеђују све остале компоненте апликације.
@HiltAndroidApp
class MyApplication : Application()
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var apiService: ApiService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// apiService је већ убризган пре позива 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 — анотација за Activity, Fragment, Service, BroadcastReceiver и View. Генерише Hilt компоненту за сваки тип: @AndroidEntryPoint на Activity креира ActivityComponent, који наслеђује од SingletonComponent. Дете компонента аутоматски прима све зависности родитеља. Field injection са @Inject lateinit var доступан је само у класама анотираним са @AndroidEntryPoint — у обичним класама користи се constructor injection.
@InstallIn указује у коју Hilt компоненту се инсталира модул. NetworkModule са @InstallIn(SingletonComponent::class) доступан је у целој апликацији. Module са @InstallIn(ActivityComponent::class) — само у Activity. Ово изолује графове зависности: модули специфични за Activity нису видљиви у Fragment и ViewModel, спречавајући случајно коришћење недозвољених зависности. @ApplicationContext — уграђени квалификатор Hilt-а за добијање контекста апликације.
Када је потребно убризгати две различите имплементације истог интерфејса, користе се квалификатори. Hilt подржава @Named за текстуалне идентификаторе и прилагођене анотације са @Qualifier. На пример, @Named("baseUrl") и @Named("imageBaseUrl") за различите текстуалне конфигурације. Прилагођени квалификатори су пожељнији од @Named због провере у фази компилације — нетачно име текста неће бити откривено до рантиме-а.
@HiltViewModel — анотација која замењује ручну фабрику ViewModelProvider.Factory. Класа анотирана са @HiltViewModel са @Inject constructor аутоматски прима све зависности кроз Dagger. Hilt генерише ViewModelFactory коју користи Jetpack ViewModelProvider. Без Hilt-а, програмер би морао да пише фабрику ручно, преносећи сваки параметар из Activity или фрагмента.
@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()
}
}
}
// У Activity — Hilt аутоматски креира ViewModel
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
}
ViewModelScoped — Hilt scope за зависности које живе док живи ViewModel. Ако два ViewModel истог типа убризгавају исту @ViewModelScoped зависност, сваки добија своју инстанцу. Ово разликује @ViewModelScoped од @ActivityScoped, где једно Activity добија једну инстанцу за све фрагменте. За ViewModel-специфичне зависности (нпр. SavedStateHandle) користи се @HiltViewModel са @Inject constructor(savedStateHandle: SavedStateHandle).
Hilt подржава assisted injection кроз библиотеку Hilt Extensions. Assisted injection омогућава прослеђивање параметара конструктору током убризгавања, када је део зависности познат само у рантиме-у (нпр. ID корисника из intent-а). За assisted injection користи се @AssistedInject у комбинацији са @Assisted параметрима. Hilt генерише AssistedFactory, која се може убризгати на стандардан начин.
Чисти Dagger захтева ручно креирање Component, дефинисање scope-ова и подешавање убризгавања у свакој Android компоненти. Програмер креира AppComponent, ActivityComponent, FragmentComponent, управља њиховим везама кроз @Subcomponent. Овај приступ пружа максималну контролу, али захтева значајну количину boilerplate кода. Dagger се користи у великим пројектима где је потребна прилагођена DI архитектура или у не-Android Java/Kotlin пројектима.
Hilt аутоматизује boilerplate: један @HiltAndroidApp, један @AndroidEntryPoint за сваку компоненту, предефинисани scope-ови. Hilt препоручује Google за све нове Android пројекте. Миграција са Dagger-а на Hilt укључује замену Component са @InstallIn, замену @Subcomponent са предефинисаним Hilt компонентама и замену ручног ViewModelProvider.Factory са @HiltViewModel. Већина @Module класа се преноси са додавањем @InstallIn без измене @Provides метода.
| Карактеристика | Dagger | Hilt |
|---|---|---|
| Подешавање | Ручно: Component, Subcomponent, Builder | Ауто: @HiltAndroidApp, @AndroidEntryPoint |
| Android компоненте | Нема предефинисаних | 12+ уграђених компонената |
| ViewModel | Ручна фабрика | @HiltViewModel + @Inject constructor |
| Мултимодул | Кроз @Component(dependencies) | Кроз @InstallIn + агрегацију |
| Сложеност | Висока — потребно искуство | Ниска — интуитивна |
| Флексибилност | Максимална | Стандардна (покрива 95% сценарија) |
Ограничења Hilt-а: библиотека подржава само Android (није погодна за чисто серверске Java пројекте), намеће одређену структуру компонената (тешко је превазићи) и додаје зависност од android.hilt:hilt-navigation-compose за Jetpack Compose пројекте. За Compose апликације, Hilt пружа @HiltViewModel доступан у Composable-у кроз hiltViewModel() — без ручног обезбеђивања ViewModel из Activity.
Често постављана питања
Dagger — основни DI фрејмворк за време компилације са ручним подешавањем Component и Module. Hilt — надградња за Android која аутоматизује креирање компонената и интеграцију са животним циклусом Activity, Fragment, ViewModel, Service и BroadcastReceiver-а.
@HiltAndroidApp укључује генерисање Hilt компоненте за Application. Без ове анотације Hilt не може креирати основну компоненту SingletonComponent, од које наслеђују сви ActivityComponent, FragmentComponent и ViewModelComponent. Анотација је обавезна за сваки Hilt пројекат.
Hilt Navigation пружа @HiltViewModel за ViewModel у NavBackStackEntry и hiltNavGraphViewModels() за скоуповање ViewModel у оквиру навигационог графа. Библиотека android.hilt:hilt-navigation-fragment аутоматски креира ViewModel за сваки NavBackStackEntry.
Користите @ApplicationContext за контекст апликације или @ActivityContext за контекст Activity. Hilt пружа ове квалификаторе уграђене у библиотеку android.hilt:hilt-android. @ActivityContext је доступан само у модулима инсталираним у ActivityComponent.
@Binds — ефикасна алтернатива за @Provides, када метод прима тачно један параметар и враћа његов тип као интерфејс. @Binds генерише директан cast без позивања метода, што смањује количину генерисаног кода и повећава перформансе при убризгавању.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође