A Koin egy DI keretrendszer Kotlinhoz, amely kódgenerálás, reflekció és annotációk nélkül működik. A könyvtár DSL-t használ a modulok leírásához és függőségeket injektál egy könnyű konténeren keresztül, Android, Ktor és Multiplatform támogatással. A Koin hivatalos dokumentációja szerint a keretrendszer modulokat, scope-okat és beépített Jetpack Compose támogatást nyújt minimális boilerplate kóddal.
Főbb pontok
Koin — DI keretrendszer Kotlinhoz, tiszta nyelven megírva, reflekció, annotációk és kódgenerálás használata nélkül. Ellentétben a Dagger Hilt-tel, amely annotációs processzort és kódgenerálást igényel a fordítási fázisban, a Koin kizárólag futásidőben működik, könnyű DSL-t használva a modulok leírásához.
A Koin fő gondolata, hogy egyszerű API-t biztosítson a függőségek regisztrálásához és feloldásához anélkül, hogy a bonyolult függőségi gráfok és komponensfák koncepcióit kellene tanulni. A fejlesztő leírja, hogy mely osztályok érhetők el a konténer számára, és a Koin automatikusan injektálja azokat a konstruktoron vagy lusta by inject delegáltakon keresztül. A keretrendszer teljesen kompatibilis a Kotlin Multiplatformmal, lehetővé téve egységes DI megközelítés használatát Androidon, iOS-en és a szerver oldalon.
A Kotlin Developers Community felmérése (2025) szerint a Koint a kereskedelmi Android projektek 31%-ában használják, népszerűségben csak a Hilt (47%) előzi meg. A választás fő oka — a konfiguráció egyszerűsége és a kódgenerálás szükségtelensége, ami gyorsítja a projekt építését.
Válassza a Koint közepes és nagy projektekhez, ahol fontos a fejlesztés gyors elindítása, vagy Kotlin Multiplatform megoldásokhoz, ahol a Hilt architektúrai okokból nem érhető el.
A Koin nem használ reflekciót és kódgenerálást — minden regisztráció inline függvényeken alapul reified típusokkal, amelyek a fordítási fázisban behelyettesítik a konkrét típust a függvény törzsébe. Ez teszi a Koint az egyik legkönnyebb DI keretrendszerré a végső APK méretét tekintve: a Koin hozzáadása csak 100–150 KB-tal növeli az alkalmazás méretét, míg a Dagger Hilt kb. 500 KB-ot ad hozzá a generált kód miatt.
A Koin konténer a startKoin függvényen keresztül inicializálódik, amely egy lambdát fogad konfigurációval. Ezen a lambdán belül írhatók le a modulok regisztrációkkal — a DI logika fő építőeleme.
A startKoin függvény globális konténert hoz létre, amely az alkalmazás bármely pontjáról elérhető a GlobalContexten keresztül, de többmodulos projektekben ajánlott a KoinApplication használata izolált konténerek létrehozásához. Androidban az inicializáláshoz az AndroidContextet használják, amely automatikusan az Application életciklusához kötődik. A modulok a modules paraméteren keresztül regisztrálhatók, amely Module példányok listáját fogadja.
val networkModule = module {
single {
OkHttpClient()
}
single {
Retrofit.Builder()
.baseUrl("https://api.example.com")
.build()
}
}
startKoin {
modules(networkModule)
}
Minden modul single (singleton) vagy factory (új példány) definíciókat tartalmaz. A definíciók hivatkozhatnak más regisztrált függőségekre a get()-en keresztül, ami egy injekciós gráfot képez explicit típusmegadás és boilerplate kód nélkül.
A Koin aktívan használ inline függvényeket reified paraméterekkel a típus következtetésére a kontextusból. Ez lehetővé teszi a regisztrációk írását az osztály explicit megadása nélkül: a single { MyService() } automatikusan meghatározza a típust a lambda visszatérési értéke alapján.
Ellentétben a Daggerrel, a Koin nem ellenőrzi a függőségi gráfot fordítási időben — minden hiba futásidőben derül ki, az első hozzáféréskor egy feloldatlan függőséghez. Ez egy kompromisszum, ami jelentősen leegyszerűsíti a kódot és gyorsítja az építést, de tesztlefedettséget igényel a DI konfigurációhoz. Számos csapat éppen a fejlesztési sebesség és egyszerűség miatt választja a Koint, a fordítási idejű ellenőrzések hiánya ellenére.
A Koin 3.5 verziójában megjelent a gráf kísérleti ellenőrzése fordítási időben a Koin Annotations bővítményen keresztül. A fejlesztő hozzáadja a @Module és @KoinComponent annotációkat, és a bővítmény validációs kódot generál, amely az építés során fut. Azonban a Koin fő előnye — a kódgenerálás hiánya — ebben a módban elveszik, ezért a legtöbb csapat továbbra is a klasszikus DSL megközelítést használja futásidőbeni ellenőrzésekkel, teszteken keresztül.
Koin több módot kínál a függőségek injektálására: by inject(), get() és közvetlen átadás a konstruktoron keresztül. A mód kiválasztása a használati kontextustól függ.
A by inject delegált — a leggyakoribb injektálási mód ViewModel és Android fragmentek esetén. A függőség lustán inicializálódik — csak a tulajdonság első elérésekor. Ez hatékony olyan erőforrás-igényes szolgáltatások esetén, amelyekre azonnal lehet, hogy nincs szükség.
class MainViewModel : ViewModel() {
private val repository: UserRepository by inject()
fun loadUsers() {
repository.fetchAll()
}
}
A get függvény azonnal visszaadja a függőség példányát. Gyári lambdákon belül használják regisztrációkor, vagy amikor a függőségre szinkron kontextusban van szükség lusta inicializálás nélkül. A by inject()-tel ellentétben a get() nem támogatja a lusta betöltést és megköveteli, hogy a konténer már inicializálva legyen a hívás pillanatában.
Scope a Koinban — mechanizmus a függőségek élettartamának egy adott komponenshez kötéséhez, mint például Activity, Fragment vagy felhasználói munkamenet. Ez egy kulcsfontosságú funkcionalitás a memóriagazdálkodáshoz Android alkalmazásokban.
A scope függvény a modulon belül létrehoz egy scope-ot, amely addig él, amíg a kapcsolódó komponens él. A scope-ban regisztrált összes függőség megsemmisül a lezárásakor, megakadályozva a memóriaszivárgást.
val userScope = module {
scope<UserSession> {
scoped {
UserRepository(get())
}
scoped {
SessionManager(get())
}
}
}
A scoped függvény olyan függőséget regisztrál, amely csak a scope-on belül létezik. A scope lezárásakor az összes scoped objektum elérhetetlenné válik a szemétgyűjtő számára.
single — egyetlen példány regisztrációja a teljes alkalmazás számára lusta inicializálással. Állapot nélküli szolgáltatásokhoz használják: hálózati kliensek, gyorsítótárak, naplózók.
factory — minden get() hívás új példányt hoz létre. ViewModel-ekhez, repo-zitóriumokhoz és állapottal rendelkező objektumokhoz alkalmazzák, ahol minden hozzáférésnél fontos a friss példány.
A Koin integrálása egy Android projektbe minimális: elég hozzáadni a függőséget a build.gradle-ben és meghívni a startKoint az Application.onCreate-ben. A Koin modulokat biztosít a Jetpack Compose, Navigation és WorkManager integrációjához, így teljes értékű alternatívája a Hiltnek.
A speciális koin-android-compose könyvtár lehetővé teszi a függőségek közvetlen injektálását Composable függvényekbe a koinViewModel() és koinInject() függvényeken keresztül. Ez kükszöböli a konténer paramétereken keresztül történő átadásának szükségességét minden képernyőnél és tisztábbá teszi a ViewModel kódot az automatikus életciklushoz kötés révén.
A Google I/O 2024 szerint a Jetpack Compose lett a fő keretrendszer új Android projektekhez. A Koin natív Compose támogatást nyújt további konfiguráció nélkül, automatikusan összekapcsolja a scope-okat a ViewModel életciklusával a koinViewModel()-en keresztül, figyelembe véve a coroutine kontextust.
Teszteléshez a Koin a koinTest és koinTestRule függvényeket biztosítja, amelyek izolált tesztkonténert hoznak létre tesztmodulokkal és a teszt befejezése után automatikusan lezárják azt. Ez biztosítja a tesztek izolációját és megakadályozza az állapot szivárgását a tesztesetek között.
A Koin Jetpack Navigationnal való integrációja a koin-androidx-navigation modulon keresztül valósul meg. Minden képernyő ViewModellje automatikusan megkapja a függőségeket a by viewModel()-en keresztül, SavedStateHandle átadásával az állapot megőrzéséhez képernyőelforgatáskor és helyreállításhoz az alkalmazás minimalizálása után.
A ViewModel egységteszteléséhez Koinnal a koin-test-junit5 vagy koin-test-junit4 könyvtár koinTestRule-ját használják. A szabály minden teszt előtt izolált konténert hoz létre tesztmodulokkal, és a teszt befejezése után automatikusan lezárja, megakadályozva az állapot szivárgását a tesztesetek között. A valós függőségeket mock-okkal helyettesítik a MockK-n keresztül: a single
A Koin 3.x egyik kulcsképessége a Ktor támogatása szerveralkalmazások létrehozásához Kotlinban és a Compose Multiplatform támogatása asztali alkalmazásokhoz. Ez teszi a Koint az egyetlen DI keretrendszerré, amely mindhárom Kotlin platformot lefedi anélkül, hogy megváltoztatná az injektálási paradigmát. A koin-ktor modul lehetővé teszi függőségek regisztrálását az install(Koin) segítségével az Application blokkban és szolgáltatások injektálását útvonalakba a by inject()-en keresztül, ugyanúgy, mint Androidban. Ez teszi a Koint univerzális DI megoldássá bármilyen architektúrájú Kotlin projekt számára — a mobil klienstől a szerver backendig.
A Koin Jetpack Navigationnal való integrációja a koin-androidx-navigation modulon keresztül kükszöböli a ViewModelProvider.Factory manuális létrehozásának szükségességét minden képernyőhöz. Többmodulos projektekhez a Koin támogatja a modulok lusta betöltését a loadKoinModules segítségével, lehetővé téve minden funkciómodul DI konfigurációjának független csatlakoztatását.
Gyakran ismételt kérdések
Koin futásidőben működik kódgenerálás és annotációk nélkül, ami gyorsítja az építést, de nem ellenőrzi a függőségi gráfot fordítási időben. A Hilt kódot generál fordításkor és korábban észleli a DI hibákat, de összetett konfigurációt igényel és lassítja az építést.
Igen, a Koin teljes mértékben támogatja a Kotlin Multiplatformot. A koin-core könyvtár minden Kotlin platformon működik, a koin-android és koin-compose pedig platform-specifikus képességeket ad Androidhoz és iOS-hez.
A ciklikus függőségek StackOverflowError-hoz vezetnek futásidőben. A Koin nem észleli őket automatikusan. Megoldás — az architektúra átalakítása: közös interfész kiemelése, Listener/Observer minta használata, vagy a ciklus megszakítása egy gyáron keresztül késleltetett inicializálással.
Androidban a scope-ok az AndroidScope-on keresztül köthetők az Activity vagy Fragment életciklusához. A komponens megsemmisülésekor a Koin automatikusan lezárja a megfelelő scope-ot. Egyéni scope-okban (felhasználói munkamenet) a lezárás manuálisan történik a scope.close hívással.
Használja a koinTest függvényt a koin-test modulból. Ez egy izolált konténert hoz létre tesztmodulokkal, amely a teszt után automatikusan bezáródik. A valós függőségeket mock-okkal helyettesítik egy modulon keresztül Mockito vagy MockK segítségével.
Összefoglaló
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