Koin — was es ist, Prinzipien der Dependency Injection und wie es funktioniert

Autor: IT Sectr Veröffentlicht: 2026-05-04 Lesezeit: 8 Min.

Koin ist ein DI-Framework für Kotlin, das ohne Codegenerierung, Reflexion und Annotationen arbeitet. Die Bibliothek verwendet DSL zur Beschreibung von Modulen und injiziert Abhängigkeiten über einen leichten Container mit Unterstützung für Android, Ktor und Multiplatform. Laut der offiziellen Koin-Dokumentation bietet das Framework Module, Scopes und integrierte Unterstützung für Jetpack Compose mit minimalem Boilerplate.

Wichtige Punkte

  • Koin ist ein DI-Framework für Kotlin, das DSL ohne Reflexion oder Codegenerierung verwendet.
  • Modul ist eine logische Gruppierung von Abhängigkeitsregistrierungen über die Funktionen single und factory.
  • single registriert ein Singleton, dessen Instanz einmal erstellt wird.
  • factory erstellt bei jeder Anfrage eine neue Instanz.
  • Scope ist ein Mechanismus, der die Lebensdauer einer Abhängigkeit an eine Komponente wie eine Activity bindet.

Was ist Koin und wie unterscheidet es sich

Koin ist ein DI-Framework für Kotlin, das in reiner Sprache ohne Reflexion, Annotationen oder Codegenerierung geschrieben ist. Im Gegensatz zu Dagger Hilt, das einen Annotationsprozessor und Codegenerierung zur Kompilierzeit erfordert, arbeitet Koin ausschließlich zur Laufzeit mit einem leichten DSL zur Beschreibung von Modulen.

Die Hauptidee von Koin ist es, eine einfache API zum Registrieren und Auflösen von Abhängigkeiten bereitzustellen, ohne komplexe Konzepte von Abhängigkeitsgraphen und Komponentenbäumen erlernen zu müssen. Der Entwickler beschreibt, welche Klassen für den Container verfügbar sind, und Koin injiziert sie automatisch über den Konstruktor oder faule Delegaten by inject. Das Framework ist vollständig mit Kotlin Multiplatform kompatibel, was einen einheitlichen DI-Ansatz auf Android, iOS und der Serverseite ermöglicht.

Laut der Umfrage der Kotlin Developers Community (2025) wird Koin in 31% der kommerziellen Android-Projekte verwendet und liegt damit nur hinter Hilt (47%). Der Hauptgrund für die Wahl ist die einfache Einrichtung und die fehlende Notwendigkeit der Codegenerierung, was den Projektbuild beschleunigt.

Wählen Sie Koin für mittlere und große Projekte, bei denen ein schneller Entwicklungsstart wichtig ist, oder für Kotlin Multiplatform-Lösungen, bei denen Hilt aus architektonischen Gründen nicht verfügbar ist.

Koin verwendet keine Reflexion oder Codegenerierung — alle Registrierungen basieren auf Inline-Funktionen mit reified-Typen, die zur Kompilierzeit den konkreten Typ in den Funktionskörper einsetzen. Dies macht Koin zu einem der leichtesten DI-Frameworks in Bezug auf die endgültige APK-Größe: Das Hinzufügen von Koin erhöht die Anwendungsgröße um nur 100-150 KB, während Dagger Hilt aufgrund von generiertem Code etwa 500 KB hinzufügt.

Wie der Koin-Container und DSL funktionieren

Der Koin-Container wird über die Funktion startKoin initialisiert, die eine Lambda mit Konfiguration akzeptiert. Innerhalb dieser Lambda werden die Module mit Registrierungen — der Hauptbaustein der DI-Logik — beschrieben.

startKoin und Module

Die Funktion startKoin erstellt einen globalen Container, der über GlobalContext von überall in der Anwendung aus zugänglich ist. In Multi-Modul-Projekten wird jedoch empfohlen, KoinApplication zu verwenden, um isolierte Container zu erstellen. In Android wird AndroidContext für die Initialisierung verwendet, der automatisch an den Application-Lebenszyklus gebunden wird. Module werden über den Parameter modules registriert, der eine Liste von Modulinstanzen akzeptiert.

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

startKoin {
    modules(networkModule)
}

Jedes Modul enthält Definitionen über single (Singleton) oder factory (neue Instanz). Definitionen können über get() auf andere registrierte Abhängigkeiten verweisen und so einen Injektionsgraphen ohne explizite Typangabe und ohne Boilerplate-Code bilden.

DSL und Inline-Funktionen

Koin verwendet aktiv Inline-Funktionen mit reified-Parametern zur Typinferenz aus dem Kontext. Dies ermöglicht das Schreiben von Registrierungen ohne explizite Angabe der Klasse: single { MyService() } bestimmt automatisch den Typ aus dem Rückgabewert der Lambda.

Im Gegensatz zu Dagger überprüft Koin den Abhängigkeitsgraphen nicht zur Kompilierzeit — alle Fehler werden zur Laufzeit beim ersten Zugriff auf eine nicht aufgelöste Abhängigkeit erkannt. Dies ist ein Kompromiss, der den Code erheblich vereinfacht und Builds beschleunigt, aber eine Testabdeckung der DI-Konfiguration erfordert. Viele Teams wählen Koin genau wegen der Entwicklungsgeschwindigkeit und Einfachheit, trotz des Fehlens von Kompilierzeitprüfungen.

In Koin Version 3.5 erschien die experimentelle Kompilierzeit-Graphenprüfung über das Plugin Koin Annotations. Der Entwickler fügt die Annotationen @Module und @KoinComponent hinzu, und das Plugin generiert Validierungscode, der beim Build ausgeführt wird. Allerdings geht der Hauptvorteil von Koin — keine Codegenerierung — in diesem Modus verloren, daher verwenden die meisten Teams weiterhin den klassischen DSL-Ansatz mit Laufzeitprüfungen durch Tests.

Methoden der Abhängigkeitsinjektion in Koin

Koin bietet mehrere Möglichkeiten, Abhängigkeiten zu injizieren: by inject(), get() und direkte Konstruktorübergabe. Die Wahl hängt vom Nutzungskontext ab.

by inject() — verzögerte Injektion

Der Delegat by inject ist die gebräuchlichste Injektionsmethode in Android-ViewModels und -Fragmenten. Die Abhängigkeit wird verzögert initialisiert — erst beim ersten Zugriff auf die Eigenschaft. Dies ist effizient für ressourcenintensive Dienste, die möglicherweise nicht sofort benötigt werden.

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

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

get() — expliziter Abruf

Die Funktion get gibt sofort eine Abhängigkeitsinstanz zurück. Sie wird innerhalb von Factory-Lambdas bei der Registrierung oder wenn die Abhängigkeit in einem synchronen Kontext ohne verzögerte Initialisierung benötigt wird, verwendet. Im Gegensatz zu by inject() unterstützt get() kein verzögertes Laden und erfordert, dass der Container zum Zeitpunkt des Aufrufs bereits initialisiert ist.

Module und Scopes in Koin

Scope in Koin ist ein Mechanismus, der die Lebensdauer von Abhängigkeiten an eine bestimmte Komponente wie eine Activity, ein Fragment oder eine benutzerdefinierte Sitzung bindet. Dies ist eine Schlüsselfunktion für die Speicherverwaltung in Android-Anwendungen.

scope — Bindung an eine Komponente

Die Funktion scope innerhalb eines Moduls erstellt einen Scope, der so lange lebt, wie die gebundene Komponente lebt. Alle im Scope registrierten Abhängigkeiten werden beim Schließen zerstört, was Speicherlecks verhindert.

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

Die Funktion scoped registriert eine Abhängigkeit, die nur innerhalb des Scopes existiert. Beim Schließen des Scopes werden alle scoped-Objekte für die Garbage Collection verfügbar.

single vs factory

single registriert eine einzelne Instanz für die gesamte Anwendung mit verzögerter Initialisierung. Wird für zustandslose Dienste verwendet: Netzwerkclients, Caches, Logger.

factory erstellt bei jedem get()-Aufruf eine neue Instanz. Wird für ViewModel, Repositories und zustandsbehaftete Objekte verwendet, bei denen bei jedem Zugriff eine frische Instanz wichtig ist.

Koin in Android-Projekten

Die Integration von Koin in ein Android-Projekt ist minimal: Fügen Sie einfach eine Abhängigkeit in build.gradle hinzu und rufen Sie startKoin in Application.onCreate auf. Koin bietet Module für die Integration mit Jetpack Compose, Navigation und WorkManager, was es zu einer vollwertigen Alternative zu Hilt macht.

Die spezielle Bibliothek koin-android-compose ermöglicht das Injizieren von Abhängigkeiten direkt in Composable-Funktionen über koinViewModel() und koinInject(). Dies macht das Durchreichen des Containers über Parameter jedes Bildschirms überflüssig und sorgt durch automatische Lebenszyklusbindung für saubereren ViewModel-Code.

Laut Google I/O 2024 wurde Jetpack Compose zum primären Framework für neue Android-Projekte. Koin bietet native Compose-Unterstützung ohne zusätzliche Konfiguration und bindet Scopes automatisch über koinViewModel() an den ViewModel-Lebenszyklus unter Berücksichtigung des Coroutine-Kontexts.

Für Tests stellt Koin die Funktionen koinTest und koinTestRule bereit, die einen isolierten Testcontainer mit Testmodulen erstellen und nach Abschluss des Tests automatisch schließen. Dies gewährleistet die Testisolierung und verhindert Zustandslecks zwischen Testfällen.

Die Koin-Integration mit Jetpack Navigation wird über das Modul koin-androidx-navigation implementiert. Das ViewModel jedes Bildschirms erhält automatisch Abhängigkeiten über by viewModel() mit Übergabe von SavedStateHandle zur Zustandserhaltung bei Bildschirmdrehung und Wiederherstellung nach Anwendungsunterbrechung.

Für Unit-Tests von ViewModel mit Koin wird koinTestRule aus der Bibliothek koin-test-junit5 oder koin-test-junit4 verwendet. Die Regel erstellt vor jedem Test einen isolierten Container mit Testmodulen und schließt ihn nach Abschluss automatisch, um Zustandslecks zwischen Testfällen zu verhindern. Reale Abhängigkeiten werden über MockK durch Mocks ersetzt: Ein Modul mit Registrierungen single { mockk() } überschreibt das Hauptmodul, und das ViewModel im Test erhält ein vorhersagbares Abhängigkeitsverhalten.

Eine der wichtigsten Funktionen von Koin 3.x ist die Unterstützung von Ktor für die Erstellung von Serveranwendungen in Kotlin und Compose Multiplatform für Desktop-Anwendungen. Dies macht Koin zum einzigen DI-Framework, das alle drei Kotlin-Plattformen abdeckt, ohne das Injektionsparadigma zu ändern. Das Modul koin-ktor ermöglicht das Registrieren von Abhängigkeiten über install(Koin) im Application-Block und das Injizieren von Diensten in Routen über by inject() wie in Android. Dies macht Koin zu einer universellen DI-Lösung für Kotlin-Projekte jeder Architektur — vom mobilen Client bis zum Server-Backend.

Die Koin-Integration mit Jetpack Navigation über das Modul koin-androidx-navigation macht das manuelle Erstellen eines ViewModelProvider.Factory für jeden Bildschirm überflüssig. Für Multi-Modul-Projekte unterstützt Koin das verzögerte Laden von Modulen über loadKoinModules, sodass jedes Feature-Modul seine DI-Konfiguration unabhängig anschließen kann.

Häufig gestellte Fragen

Wie unterscheidet sich Koin von Dagger Hilt?

Koin arbeitet zur Laufzeit ohne Codegenerierung oder Annotationen, was Builds beschleunigt, aber den Abhängigkeitsgraphen nicht zur Kompilierzeit überprüft. Hilt generiert Code zur Kompilierzeit und fängt DI-Fehler früher ab, erfordert jedoch eine komplexe Einrichtung und verlangsamt den Build.

Unterstützt Koin Kotlin Multiplatform?

Ja, Koin unterstützt Kotlin Multiplatform vollständig. Die koin-core-Bibliothek funktioniert auf allen Kotlin-Plattformen, während koin-android und koin-compose plattformspezifische Funktionen für Android bzw. iOS hinzufügen.

Wie behandelt man zirkuläre Abhängigkeiten in Koin?

Zirkuläre Abhängigkeiten führen zur Laufzeit zu einem StackOverflowError. Koin erkennt sie nicht automatisch. Die Lösung ist eine Architektur-Refaktorisierung: Extrahieren einer gemeinsamen Schnittstelle, Verwenden des Listener/Observer-Musters oder Auflösen des Zyklus durch eine Factory mit verzögerter Initialisierung.

Muss ich Scopes manuell schließen?

In Android können Scopes über AndroidScope an den Lebenszyklus einer Activity oder eines Fragments gebunden werden. Wenn die Komponente zerstört wird, schließt Koin automatisch den entsprechenden Scope. Bei benutzerdefinierten Scopes (Benutzersitzung) erfolgt das Schließen manuell durch Aufruf von scope.close.

Wie teste ich Code mit Koin?

Verwenden Sie die Funktion koinTest aus dem Modul koin-test. Sie erstellt einen isolierten Container mit Testmodulen, der nach dem Test automatisch geschlossen wird. Reale Abhängigkeiten werden über ein Modul mit Mockito oder MockK durch Mocks ersetzt.

Zusammenfassung

  • Koin ist ein DI-Framework für Kotlin mit DSL ohne Reflexion, Annotationen oder Codegenerierung.
  • Module gruppieren Registrierungen über single (Singleton) und factory (neue Instanz).
  • startKoin initialisiert einen globalen Container, der über by inject() und get() zugänglich ist.
  • Scope bindet die Lebensdauer von Abhängigkeiten an den Lebenszyklus der Android-Komponente.
  • Die Injektion in Compose erfolgt über koinViewModel() und koinInject().
  • Koin unterstützt Kotlin Multiplatform und ermöglicht so einen einheitlichen DI-Ansatz auf allen Plattformen.
  • DI-Fehler werden zur Laufzeit erkannt, daher ist eine Testabdeckung der Konfiguration zwingend erforderlich.

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch