Dagger — egy függőséginjektálási keretrendszer Java-hoz és Kotlin-hoz, amely DI kódot generál fordítási időben annotációk feldolgozásával. Hilt — egy réteg a Dagger felett Android-hoz, amely leegyszerűsíti a komponensek és az életciklus konfigurálását. A Google, 2025 adatai szerint a Hilt a Google Play Top-100-ból több mint 70%-ában használatos, támogatva az Activity, Fragment, ViewModel és Service komponenseket előre meghatározott komponenseken keresztül. Mindkét keretrendszer biztosítja a függőségi gráf fordítási időben történő ellenőrzését, kiküszöbölve a futásidejű injektálási hibákat.
Főbb pontok
Dagger — egy függőséginjektálási keretrendszer kódgenerálással fordítási időben (compile-time DI). A Square-ben fejlesztették, majd később a Google-nak adták át, a Dagger a Java APT annotációs processzort használja a függőségi gráf elemzésére és gyári osztályok generálására. A runtime-DI-vel (Guice, Koin) ellentétben a Dagger nem használ reflexiót — minden kód fordítási időben készül, ami maximális teljesítményt biztosít futásidőben és hibafelismerést a build fázisban.
Hilt — egy Google könyvtár, amely a Dagger tetejére épül és Android-ra optimalizált. A Hilt előre meghatározott komponenseket biztosít, amelyek megfelelnek az Android komponensek életciklusának: @SingletonComponent az Application-hoz, @ActivityComponent az Activity-hez, @FragmentComponent a Fragment-hez, @ViewModelComponent a ViewModel-hez. Ez kiküszöböli a Component és Module rutinszerű konfigurálását, ami a tiszta Dagger-ben szükséges. A Hilt automatikusan generálja a függőségi gráfot minden Android komponenshez a @AndroidEntryPoint segítségével.
A Google I/O 2024 szerint a Hilt az ajánlott DI megoldás Kotlin-ban írt Android alkalmazásokhoz. A Jetpack könyvtárak (Navigation, Room, WorkManager) beépített integrációval rendelkeznek a Hilt-tel a @HiltViewModel és @HiltWorker segítségével. Azokban a projektekben, amelyek nem használnak Android-ot (tiszta Java/Kotlin könyvtárak, szerver alkalmazások), tiszta Dagger-t alkalmaznak Hilt réteg nélkül.
DI keretrendszer nélkül a fejlesztő manuálisan hozza létre az objektumokat konstruktorokon vagy gyárakon keresztül, láncban továbbadva a függőségeket. Minden új követelmény — az összes konstruktor aláírásának megváltoztatása a láncban. Dagger automatizálja ezt a folyamatot: elég deklarálni, hogy milyen típusra van szükség (@Inject constructor), és a Dagger létrehozza a függőségi gráfot, megoldva az összes beágyazott típust. A függőségek változásakor a Dagger automatikusan frissíti a generált kódot — lehetetlen hibázni a láncban.
Függőséginjektálás (Dependency Injection) — egy minta, amelyben egy objektum kívülről kapja meg a függőségeit, ahelyett, hogy maga hozná létre azokat. A DI megvalósítja az inverzió vezérlés (IoC) elvét: az osztály nem felelős a saját függőségei létrehozásáért, hanem azokat konstruktoron, metóduson vagy mezőn keresztül deklarálja. A konstruktoron keresztüli injektálás (constructor injection) tekinthető a legkedveltebbnek, mert garantálja, hogy az objektum érvényes állapotban jön létre.
| Injektálás típusa | Dagger szintaxis | Mikor használjuk |
|---|---|---|
| Constructor injection | @Inject constructor | Fő módszer — minden saját osztályhoz |
| Field injection | @Inject lateinit var | Csak Android komponensekhez (Activity, Fragment) |
| Method injection | @Inject fun bind() | Post-construct inicializáláshoz |
A DI fő előnyei közé tartozik a tesztelhetőség (a függőségek mock objektumokkal helyettesíthetők), laza csatolás (az osztályok interfészektől függnek, nem implementációktól), és az objektumok életciklusának explicit kezelése scope-okon keresztül. Dagger automatikusan garantálja, hogy egy objektum egyszer jön létre a saját scope-ján belül, és megsemmisül a scope elhagyásakor.
Component — a Dagger függőségi gráf központi eleme. Ez egy @Component annotációval ellátott interfész, amely leírja a hidat a Module és az injektálási célok között. A Dagger generálja a Component implementációját (pl. DaggerAppComponent) fordítási időben. A Component meghatározza, mely típusok állnak rendelkezésre injektáláshoz, absztrakt metódusokon keresztül, amelyek visszaadják a szükséges típusokat, vagy inject metódusokon keresztül, amelyek egy objektumot fogadnak el field injection-hez.
// Modul: olyan függőségeket biztosít, amelyeket a Dagger nem tud létrehozni
@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)
}
}
// Komponens: összeköti a Module-t és az injektálási célokat
@Component(modules = [NetworkModule::class])
interface AppComponent {
fun inject(activity: MainActivity)
fun getApiService(): ApiService
}
@Module — egy osztály, amely @Provides metódusokat tartalmaz, amelyek függőségi példányokat adnak vissza. A Module olyan típusokhoz használatos, amelyeket a Dagger nem tud automatikusan létrehozni: harmadik féltől származó könyvtárak (OkHttp, Retrofit), konstruktor paraméterekkel rendelkező objektumok, implementációválasztással rendelkező interfészek. @Binds — alternatíva a @Provides számára olyan esetekben, amikor a metódus egy interfészt ad vissza és egyetlen implementációt fogad: a Dagger közvetlen cast-ot generál a metódus meghívása nélkül.
@Scope meghatározza az objektum élettartamát a függőségi gráfban. @Singleton — az objektum egyszer jön létre a teljes alkalmazáshoz. @ActivityScoped — az objektum addig él, amíg az Activity él. @FragmentScoped — amíg a Fragment él. Scope nélkül a Dagger minden injektáláskor új példányt hoz létre. @Reusable — olyan objektumok scope-ja, amelyeknek nem kell singleton-nak lenniük, de létrehozásuk költséges — a Dagger gyorsítótárazhatja a példányt, de nem garantálja ezt.
Hilt leegyszerűsíti a Dagger konfigurálását Android-hoz az előre meghatározott komponenseknek és az alapgráf automatikus generálásának köszönhetően. A @HiltAndroidApp annotáció az Application osztályon elindítja a Hilt komponens generálását. Ezen annotáció nélkül a Hilt nem működik — kötelező minden Hilt-et használó Android alkalmazáshoz. A @HiltAndroidApp létrehozza a szülő SingletonComponent komponenst, amelytől az alkalmazás összes többi komponense örököl.
@HiltAndroidApp
class MyApplication : Application()
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var apiService: ApiService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// az apiService már injektálva lett az onCreate hívása előtt
}
}
@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 — annotáció Activity, Fragment, Service, BroadcastReceiver és View számára. Hilt komponenst generál minden típushoz: az Activity-n lévő @AndroidEntryPoint létrehozza az ActivityComponent-ot, amely a SingletonComponent-től örököl. A gyermek komponens automatikusan megkapja a szülő összes függőségét. A @Inject lateinit var field injection csak a @AndroidEntryPoint annotációval ellátott osztályokban érhető el — a hétköznapi osztályokban constructor injection használatos.
@InstallIn jelzi, hogy a modul melyik Hilt komponensbe kerül telepítésre. A @InstallIn(SingletonComponent::class) NetworkModule a teljes alkalmazásban elérhető. A @InstallIn(ActivityComponent::class) Module — csak Activity-ben. Ez elkülöníti a függőségi gráfokat: az Activity-specifikus modulok nem láthatók a Fragment-ben és ViewModel-ben, megakadályozva a nem engedélyezett függőségek véletlen használatát. @ApplicationContext — a Hilt beépített minősítője az alkalmazás kontextusának lekéréséhez.
Amikor ugyanazon interfész két különböző implementációját kell injektálni, minősítőket használunk. A Hilt támogatja a @Named annotációt szöveges azonosítókhoz és egyéni annotációkat a @Qualifier-rel. Például @Named("baseUrl") és @Named("imageBaseUrl") különböző szöveges konfigurációkhoz. Az egyéni minősítők előnyösebbek a @Named-nél a fordítási időben történő ellenőrzés miatt — a helytelen szöveges név csak futásidőben derül ki.
@HiltViewModel — annotáció, amely helyettesíti a kézi ViewModelProvider.Factory gyárat. A @HiltViewModel annotációval és @Inject constructor-ral ellátott osztály automatikusan megkapja az összes függőséget a Dagger-en keresztül. A Hilt generálja a ViewModelFactory-t, amelyet a Jetpack ViewModelProvider használ. Hilt nélkül a fejlesztőnek kézzel kellene megírnia a gyárat, minden paramétert az Activity-ből vagy fragment-ből átadva.
@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-ben — a Hilt automatikusan létrehozza a ViewModel-t
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
}
ViewModelScoped — Hilt scope olyan függőségekhez, amelyek addig élnek, amíg a ViewModel él. Ha két azonos típusú ViewModel ugyanazt a @ViewModelScoped függőséget injektálja, mindegyik saját példányt kap. Ez különbözteti meg a @ViewModelScoped-ot a @ActivityScoped-tól, ahol egy Activity egy példányt kap az összes fragment számára. ViewMmodell-specifikus függőségekhez (pl. SavedStateHandle) használja a @HiltViewModel-t @Inject constructor(savedStateHandle: SavedStateHandle) formában.
A Hilt támogatja az assisted injection-t a Hilt Extensions könyvtáron keresztül. Az assisted injection lehetővé teszi paraméterek átadását a konstruktornak injektálás közben, amikor a függőségek egy része csak futásidőben ismert (pl. felhasználói ID intent-ből). Az assisted injection-hez a @AssistedInject használandó @Assisted paraméterekkel kombinálva. A Hilt generálja az AssistedFactory-t, amely szabványos módon injektálható.
Tiszta Dagger a Component kézi létrehozását, scope-ok meghatározását és az injektálás konfigurálását igényli minden Android komponensben. A fejlesztő létrehozza az AppComponent, ActivityComponent, FragmentComponent komponenseket, és @Subcomponent segítségével kezeli kapcsolataikat. Ez a megközelítés maximális kontrollt biztosít, de jelentős mennyiségű boilerplate kódot igényel. A Dagger nagy projektekben használatos, ahol egyedi DI architektúra szükséges, vagy nem Android Java/Kotlin projektekben.
Hilt automatizálja a boilerplate-ot: egy @HiltAndroidApp, egy @AndroidEntryPoint minden komponenshez, előre meghatározott scope-ok. A Hilt-et a Google ajánlja minden új Android projekthez. A Dagger-ről Hilt-re migrálás magában foglalja a Component @InstallIn-nel való helyettesítését, a @Subcomponent előre meghatározott Hilt komponensekkel való helyettesítését és a kézi ViewModelProvider.Factory @HiltViewModel-lel való helyettesítését. A legtöbb @Module osztály a @Provides metódusok módosítása nélkül kerül átvitelre a @InstallIn hozzáadásával.
| Jellemző | Dagger | Hilt |
|---|---|---|
| Konfiguráció | Kézi: Component, Subcomponent, Builder | Automatikus: @HiltAndroidApp, @AndroidEntryPoint |
| Android komponensek | Nincsenek előre meghatározva | 12+ beépített komponens |
| ViewModel | Kézi gyár | @HiltViewModel + @Inject constructor |
| Többmodul | @Component(dependencies) segítségével | @InstallIn + aggregáció segítségével |
| Bonyolultság | Magas — tapasztalat szükséges | Alacsony — intuitív |
| Rugalmasság | Maximális | Szabványos (a forgatókönyvek 95%-át lefedi) |
A Hilt korlátai: a könyvtár csak Android-ot támogat (nem alkalmas tiszta szerver Java projektekhez), meghatározott komponensstruktúrát kényszerít ki (nehéz felülírni), és függőséget ad hozzá az android.hilt:hilt-navigation-compose-hoz Jetpack Compose projektekhez. Compose alkalmazásokhoz a Hilt @HiltViewModel-t biztosít, amely elérhető a Composable-ben a hiltViewModel() segítségével — anélkül, hogy manuálisan kellene biztosítani a ViewModel-t az Activity-ből.
Gyakran ismételt kérdések
Dagger — alap compile-time DI keretrendszer a Component és Module kézi konfigurálásával. Hilt — Android réteg, amely automatizálja a komponensek létrehozását és integrációját az Activity, Fragment, ViewModel, Service és BroadcastReceiver életciklusával.
@HiltAndroidApp bekapcsolja a Hilt komponens generálását az Application számára. Ezen annotáció nélkül a Hilt nem tudja létrehozni az alap SingletonComponent komponenst, amelytől az összes ActivityComponent, FragmentComponent és ViewModelComponent örököl. Az annotáció minden Hilt projekthez kötelező.
Hilt Navigation @HiltViewModel-t biztosít a ViewModel számára NavBackStackEntry-ben és hiltNavGraphViewModels()-t a ViewModel scope-olásához a navigációs gráfon belül. Az android.hilt:hilt-navigation-fragment könyvtár automatikusan létrehozza a ViewModel-t minden NavBackStackEntry-hez.
Használja a @ApplicationContext-et az alkalmazás kontextusához vagy a @ActivityContext-et az Activity kontextusához. A Hilt ezeket a minősítőket beépítve biztosítja az android.hilt:hilt-android könyvtárban. A @ActivityContext csak az ActivityComponent-be telepített modulokban érhető el.
@Binds — hatékony alternatíva a @Provides számára, amikor a metódus pontosan egy paramétert fogad és visszaadja annak típusát interfészként. A @Binds közvetlen cast-ot generál a metódus meghívása nélkül, ami csökkenti a generált kód mennyiségét és növeli a teljesítményt injektáláskor.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is