Koin — vad det är, Dependency Injection-principer och hur det fungerar

Författare: IT Sectr Publicerad: 2026-05-04 Lästid: 8 min

Koin är ett DI-ramverk för Kotlin som fungerar utan kodgenerering, reflektion och annoteringar. Biblioteket använder DSL för att beskriva moduler och injicerar beroenden genom en lätt container med stöd för Android, Ktor och Multiplatform. Enligt Koin officiella dokumentation tillhandahåller ramverket moduler, scopes och inbyggt stöd för Jetpack Compose med minimal boilerplate.

Huvudpunkter

  • Koin — DI-ramverk för Kotlin som använder DSL utan reflektion och kodgenerering.
  • Modul — logisk gruppering av beroenderegistreringar genom single- och factory-funktioner.
  • single — registrering av en singleton vars instans skapas en gång.
  • factory — registrering där varje begäran skapar en ny instans.
  • Scope — mekanism för att binda ett beroendes livslängd till en komponent, till exempel till en Activity.

Vad är Koin och hur skiljer det sig

Koin — DI-ramverk för Kotlin, skrivet i rent språk utan användning av reflektion, annoteringar eller kodgenerering. Till skillnad från Dagger Hilt, som kräver en annoteringsprocessor och kodgenerering vid kompilering, fungerar Koin uteslutande vid körning med hjälp av ett lätt DSL för att beskriva moduler.

Huvudidén med Koin är att tillhandahålla ett enkelt API för registrering och upplösning av beroenden utan att behöva lära sig komplexa begrepp som beroendegrafer och komponentträd. Utvecklaren beskriver vilka klasser som är tillgängliga för containern, och Koin injicerar dem automatiskt via konstruktorn eller lata by inject-delegater. Ramverket är fullt kompatibelt med Kotlin Multiplatform, vilket möjliggör en enhetlig DI-metod på Android, iOS och serversidan.

Enligt Kotlin Developers Community-enkäten (2025) används Koin i 31% av kommersiella Android-projekt, och det är bara Hilt (47%) som är mer populärt. Huvudorsaken till valet är enkelheten i konfigurationen och avsaknaden av behov av kodgenerering, vilket snabbar upp projektbygget.

Välj Koin för medelstora och stora projekt där en snabb utvecklingsstart är viktig, eller för Kotlin Multiplatform-lösningar där Hilt inte är tillgängligt av arkitektoniska skäl.

Koin använder inte reflektion och kodgenerering — alla registreringar baseras på inline-funktioner med reified-typer som vid kompilering ersätter den konkreta typen i funktionskroppen. Detta gör Koin till ett av de lättaste DI-ramverken när det gäller slutlig APK-storlek: att lägga till Koin ökar appstorleken med endast 100–150 KB, medan Dagger Hilt lägger till cirka 500 KB på grund av genererad kod.

Hur Koin container och DSL fungerar

Koin-containern Koin initieras via funktionen startKoin som tar emot en lambda med konfiguration. Inuti denna lambda beskrivs moduler med registreringar — den primära byggstenen för DI-logik.

startKoin och moduler

Funktionen startKoin skapar en global container som är tillgänglig från vilken punkt som helst i applikationen via GlobalContext, men i multimodulprojekt rekommenderas att använda KoinApplication för att skapa isolerade containrar. I Android används AndroidContext för initiering, som automatiskt binds till Application livscykel. Moduler registreras via parametern modules som tar emot en lista av Module-instanser.

kotlin
val networkModule = module {
    single {
        OkHttpClient()
    }
    single {
        Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .build()
    }
}

startKoin {
    modules(networkModule)
}

Varje modul innehåller definitioner via single (singleton) eller factory (ny instans). Definitioner kan referera till andra registrerade beroenden via get(), vilket bildar en injektionsgraf utan explicit typangivelse och utan boilerplate-kod.

DSL och inline-funktioner

Koin använder aktivt inline-funktioner med reified-parametrar för att härleda typ från kontexten. Detta gör det möjligt att skriva registreringar utan explicit klassangivelse: single { MyService() } bestämmer automatiskt typen baserat på lambdans returvärde.

Till skillnad från Dagger kontrollerar Koin inte beroendegrafen vid kompilering — alla fel upptäcks vid körning vid första åtkomst till ett olöst beroende. Detta är en kompromiss som avsevärt förenklar koden och snabbar upp bygget, men kräver testtäckning av DI-konfigurationen.

I Koin version 3.5 introducerades experimentell grafkontroll vid kompilering via Koin Annotations-plugin. Huvudfördelen med Koin — avsaknad av kodgenerering — går dock förlorad i detta läge, så de flesta team fortsätter att använda den klassiska DSL-metoden med körningskontroller via tester.

Sätt att injicera beroenden i Koin

Koin erbjuder flera sätt att injicera beroenden: by inject(), get() och direkt överföring via konstruktorn. Valet av metod beror på användningskontexten.

by inject() — lat injektion

Delegaten by inject — den vanligaste injektionsmetoden i ViewModel och Android-fragment. Beroendet initieras lätt — endast vid första åtkomst till egenskapen.

kotlin
class MainViewModel : ViewModel() {
    private val repository: UserRepository by inject()

    fun loadUsers() {
        repository.fetchAll()
    }
}

get() — explicit hämtning

Funktionen get returnerar omedelbart instansen av beroendet. Till skillnad från by inject() stöder get() inte lat laddning och kräver att containern redan är initierad vid anropstillfället.

Moduler och scopes i Koin

Scope i Koin — mekanism för att binda beroendens livslängd till en specifik komponent, såsom Activity, Fragment eller användarsession.

scope — bindning till komponent

Funktionen scope inuti en modul skapar ett scope som lever så länge den kopplade komponenten lever. Alla beroenden som registrerats i scopet förstörs när det stängs, vilket förhindrar minnesläckor.

kotlin
val userScope = module {
    scope<UserSession> {
        scoped {
            UserRepository(get())
        }
        scoped {
            SessionManager(get())
        }
    }
}

Funktionen scoped registrerar ett beroende som endast kommer att existera inom scopet.

single vs factory

single — registrering av en enda instans för hela applikationen med lat initiering. factory — varje get()-anrop skapar en ny instans, används för ViewModel, repositories och objekt med tillstånd.

Koin i Android-projekt

Integration av Koin i ett Android-projekt är minimal: lägg till beroendet i build.gradle och anropa startKoin i Application.onCreate. Koin tillhandahåller moduler för integration med Jetpack Compose, Navigation och WorkManager.

Det speciella biblioteket koin-android-compose möjliggör direkt injektion av beroenden i Composable-funktioner via koinViewModel() och koinInject().

Enligt Google I/O 2024 har Jetpack Compose blivit det primära ramverket för nya Android-projekt. Koin ger native Compose-stöd utan extra konfiguration.

För testning tillhandahåller Koin funktionerna koinTest och koinTestRule som skapar en isolerad testcontainer med testmoduler. Integration med Jetpack Navigation sker via modulen koin-androidx-navigation.

För enhetstestning av ViewModel med Koin används koinTestRule från biblioteket koin-test-junit5 eller koin-test-junit4. Verkliga beroenden ersätts med mockar via MockK.

En av nyckelfunktionerna i Koin 3.x är stöd för Ktor för att skapa serverapplikationer i Kotlin och Compose Multiplatform för skrivbordsapplikationer. Detta gör Koin till det enda DI-ramverk som täcker alla tre Kotlin-plattformar utan att ändra injektionsparadigm.

För multimodulprojekt stöder Koin lat inläsning av moduler via loadKoinModules, vilket möjliggör oberoende anslutning av DI-konfigurationen för varje feature-modul.

Vanliga frågor

Hur skiljer sig Koin från Dagger Hilt?

Koin fungerar vid körning utan kodgenerering och annoteringar, vilket snabbar upp bygget, men kontrollerar inte beroendegrafen vid kompilering. Hilt genererar kod vid kompilering och upptäcker DI-fel tidigare, men kräver komplex konfiguration och saktar ner bygget.

Stöder Koin Kotlin Multiplatform?

Ja, Koin stöder fullt ut Kotlin Multiplatform. Biblioteket koin-core fungerar på alla Kotlin-plattformar.

Hur hanterar man cykliska beroenden i Koin?

Cykliska beroenden leder till StackOverflowError vid körning. Koin upptäcker dem inte automatiskt. Lösningen är arkitekturrefaktorering.

Måste scopes stängas manuellt?

I Android kan scopes kopplas till Activity eller Fragment livscykel via AndroidScope. När komponenten förstörs stänger Koin automatiskt motsvarande scope.

Hur testar man kod med Koin?

Använd funktionen koinTest från modulen koin-test. Den skapar en isolerad container med testmoduler som automatiskt stängs efter testet.

Sammanfattning

  • Koin — DI-ramverk för Kotlin med DSL utan reflektion, annoteringar och kodgenerering.
  • Moduler grupperar registreringar via single (singleton) och factory (ny instans).
  • startKoin initierar den globala containern som är tillgänglig via by inject() och get().
  • Scope binder beroendens livslängd till Android-komponentens livscykel.
  • Injektion i Compose sker via koinViewModel() och koinInject().
  • Koin stöder Kotlin Multiplatform för en enhetlig DI-metod på alla plattformar.
  • DI-fel upptäcks vid körning, därför är testtäckning av konfigurationen obligatorisk.

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också