# Wstrzykiwanie zależności na Androidzie: Hilt vs Koin - kompletny przewodnik z pytaniami rekrutacyjnymi 2026 > Szczegółowe porównanie Hilt 2.57 i Koin 4.2 dla Android DI: walidacja w czasie kompilacji vs runtime, benchmarki wydajności, testowanie, architektura wielomodułowa i pytania rekrutacyjne. - Published: 2026-05-24 - Updated: 2026-05-24 - Author: SharpSkill - Tags: android, hilt, koin, dependency-injection, kotlin - Reading time: 12 min --- Wstrzykiwanie zależności (Dependency Injection, DI) stanowi fundament dobrze zaprojektowanej aplikacji Android. Wzorzec ten determinuje sposób, w jaki klasy otrzymują swoje zależności, eliminując konieczność ich bezpośredniego tworzenia wewnątrz obiektów. W 2026 roku ekosystem Android oferuje dwa dominujące frameworki DI: [Hilt](https://dagger.dev/hilt/) w wersji 2.57.1 — oficjalne rozwiązanie Google zbudowane na bazie Daggera, realizujące walidację grafu zależności w czasie kompilacji — oraz [Koin](https://insert-koin.io/) w wersji 4.2.1, lekki framework oparty na DSL Kotlina, rozwiązujący zależności w runtime. Wybór jednego z nich ma bezpośredni wpływ na czas budowania projektu, wydajność startu aplikacji, testowalność kodu i tempo onboardingu nowych członków zespołu. > **Walidacja w czasie kompilacji vs runtime** > > Hilt weryfikuje cały graf zależności podczas kompilacji — brakujący binding powoduje błąd buildu, zanim aplikacja zostanie uruchomiona. Koin rozwiązuje zależności w runtime za pomocą DSL Kotlina, wykrywając błędy konfiguracji dopiero w momencie wykonania danej ścieżki kodu. Ta fundamentalna różnica determinuje wszystkie kompromisy między oboma frameworkami. ## Jak działa Hilt pod maską Hilt generuje komponenty Daggera mapowane na klasy cyklu życia Androida. Adnotacja `@HiltAndroidApp` uruchamia proces generowania kodu w czasie kompilacji, tworząc fabryki i providery dla każdego zadeklarowanego bindingu. Od wersji 2.48 zalecanym procesorem adnotacji jest KSP (Kotlin Symbol Processing), który zastąpił KAPT i skrócił czas przetwarzania adnotacji o blisko połowę. Typowa konfiguracja Hilt składa się z trzech elementów: modułu deklarującego bindingi, punktu wejścia (Activity, Fragment lub ViewModel) oraz klasy Application oznaczonej adnotacją `@HiltAndroidApp`. ```kotlin // AppModule.kt @Module @InstallIn(SingletonComponent::class) object AppModule { @Provides @Singleton fun provideRetrofit(): Retrofit { return Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build() } @Provides @Singleton fun provideUserRepository( retrofit: Retrofit ): UserRepository { return UserRepositoryImpl(retrofit.create(UserApi::class.java)) } } ``` Adnotacja `@InstallIn(SingletonComponent::class)` określa zakres życia bindingów — w powyższym przykładzie są one powiązane z cyklem życia całej aplikacji. Hilt definiuje predefiniowaną hierarchię komponentów: `SingletonComponent`, `ActivityRetainedComponent`, `ViewModelComponent`, `ActivityComponent`, `FragmentComponent` i `ViewComponent`, wymuszając poprawne zarządzanie zakresami na poziomie kompilacji. ```kotlin // UserViewModel.kt @HiltViewModel class UserViewModel @Inject constructor( private val userRepository: UserRepository ) : ViewModel() { private val _users = MutableStateFlow>(emptyList()) val users: StateFlow> = _users.asStateFlow() fun loadUsers() { viewModelScope.launch { _users.value = userRepository.getUsers() } } } ``` Kompilator weryfikuje, czy `UserRepository` posiada prawidłowego providera, zanim aplikacja zostanie uruchomiona. Brakujące bindingi ujawniają się jako błędy kompilacji, a nie awarie w trakcie działania aplikacji. ## Konfiguracja Koin i podejście oparte na DSL Kotlina Koin przyjmuje diametralnie odmienne podejście: zero generowania kodu, zero przetwarzania adnotacji. Zależności deklarowane są w czystym Kotlinie za pomocą DSL, a framework rozwiązuje je w runtime poprzez globalny rejestr usług. Wersja 4.2 wprowadza lazy modules umożliwiające równoległe ładowanie modułów podczas startu aplikacji oraz nowy silnik `CoreResolverV2` optymalizujący rozwiązywanie zakresów. ```kotlin // AppModule.kt val appModule = module { // Singleton Retrofit instance single { Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build() } // Singleton repository bound to its interface single { UserRepositoryImpl(get().create(UserApi::class.java)) } // ViewModel with injected repository viewModel { UserViewModel(get()) } } ``` ```kotlin // MyApplication.kt class MyApplication : Application() { override fun onCreate() { super.onCreate() startKoin { androidContext(this@MyApplication) modules(appModule) } } } ``` DSL czyta się naturalnie i nie wymaga żadnej konfiguracji pluginu przetwarzania adnotacji w Gradle. Kompromisem jest fakt, że literówka w wywołaniu `get()` ujawni się dopiero w runtime, gdy dana ścieżka wstrzykiwania zostanie wykonana. ## Benchmarki wydajności: czas budowania vs koszt runtime Kwestia wydajności pojawia się praktycznie na każdej [rozmowie rekrutacyjnej z Androida](/technologies/android/interview-questions/android-dependency-injection). Konkretne liczby mają większą wartość niż subiektywne opinie. | Metryka | Hilt 2.57 (KSP) | Koin 4.2 | |--------|-----------------|----------| | Narzut czystego buildu | +8-15s (generowanie kodu KSP) | ~0s (brak generowania kodu) | | Narzut buildu przyrostowego | +2-4s | ~0s | | Start aplikacji (50 bindingów) | ~0ms (wygenerowany kod) | ~5-15ms (rozwiązywanie grafu) | | Start aplikacji (500 bindingów) | ~0ms | ~30-80ms | | Wpływ na rozmiar APK | +200-400 KB (wygenerowany kod) | +100 KB (biblioteka runtime) | | Wykrywanie brakujących bindingów | Błąd kompilacji | Crash w runtime | W projektach z liczbą bindingów poniżej 100 narzut runtime Koin pozostaje niezauważalny dla użytkownika. Powyżej 300 bindingów koszt startu staje się mierzalny, choć mechanizm lazy modules w Koin 4.2 łagodzi ten problem przez równoległe ładowanie modułów. > **KSP vs KAPT** > > Przejście z KAPT na KSP przy przetwarzaniu adnotacji Hilt skraca czas procesowania o 40-60%. Każdy projekt nadal wykorzystujący KAPT z Hilt powinien niezwłocznie przeprowadzić migrację do KSP. Hilt wspiera KSP od wersji 2.48. ## Strategie testowania w obu frameworkach Testowalność to obszar, w którym różnice architektoniczne przekładają się na praktykę codziennej pracy. Hilt oferuje adnotację `@TestInstallIn` do podmiany modułów produkcyjnych na testowe w czasie kompilacji. Koin udostępnia mechanizm `loadKoinModules()` do nadpisywania definicji w runtime. ```kotlin // Hilt test module — replaces AppModule bindings in tests @Module @TestInstallIn( components = [SingletonComponent::class], replaces = [AppModule::class] ) object FakeAppModule { @Provides @Singleton fun provideUserRepository(): UserRepository { return FakeUserRepository() // In-memory test double } } ``` ```kotlin // Koin test — override at runtime class UserViewModelTest : KoinTest { @Before fun setUp() { startKoin { modules( module { single { FakeUserRepository() } viewModel { UserViewModel(get()) } } ) } } @Test fun `loads users from repository`() { val viewModel: UserViewModel = get() viewModel.loadUsers() assertEquals(3, viewModel.users.value.size) } @After fun tearDown() { stopKoin() } } ``` Testy Hilt wykrywają błędnie skonfigurowane moduły testowe na etapie kompilacji. Testy Koin wymagają starannego zarządzania cyklem życia kontenera (`startKoin`/`stopKoin`), ale oferują większą elastyczność przy częściowym nadpisywaniu modułów. ## Architektura wielomodułowa: skalowanie DI między feature modules Duże projekty Android dzielą funkcjonalności na oddzielne moduły Gradle. Framework DI musi poprawnie obsługiwać granice między modułami, zachowując izolację i czytelność grafu zależności. W przypadku Hilt każdy feature module deklaruje własny moduł oznaczony adnotacją `@Module` i `@InstallIn`. Hilt scala wszystkie moduły w pojedynczą hierarchię komponentów w czasie kompilacji. [Architektura MVVM](/blog/android/mvvm-vs-mvi-architecture) naturalnie współgra ze scopowanymi komponentami Hilt. ```kotlin // feature-payments/PaymentModule.kt @Module @InstallIn(ViewModelComponent::class) object PaymentModule { @Provides fun providePaymentGateway( retrofit: Retrofit // Provided by :app module ): PaymentGateway { return StripePaymentGateway(retrofit.create(PaymentApi::class.java)) } } ``` W Koin feature modules eksportują swoje deklaracje `module {}`, a moduł aplikacji ładuje je wszystkie podczas startu. Mechanizm lazy modules w Koin 4.2 pozwala na odroczone ładowanie feature modules do momentu pierwszego dostępu. ```kotlin // feature-payments/paymentModule.kt val paymentModule = module { factory { StripePaymentGateway(get().create(PaymentApi::class.java)) } } // app/MyApplication.kt — loads all feature modules startKoin { modules(appModule, paymentModule, analyticsModule) } ``` Hilt wymusza widoczność zależności poprzez zakresy komponentów — binding zainstalowany w `ViewModelComponent` nie może wstrzyknąć zależności o krótszym cyklu życia. Koin opiera się na konwencjach zespołu: dowolny moduł ma dostęp do definicji każdego innego modułu, co daje elastyczność, ale może prowadzić do niejawnych powiązań. ## Kotlin Multiplatform a wybór frameworka DI Koin wspiera [Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html) (KMP) natywnie. Ten sam DSL `module {}` działa na platformach Android, iOS, Desktop i Web. Hilt jest rozwiązaniem wyłącznie androidowym — opiera się na komponentach cyklu życia specyficznych dla Androida oraz na procesorze adnotacji Daggera. Dla projektów celujących w wiele platform Koin pozostaje jedynym dostępnym wyborem spośród obu frameworków. Współdzielone moduły logiki biznesowej mogą deklarować swoje zależności jednokrotnie i wstrzykiwać je na wszystkich docelowych platformach. ## Najczęstsze pytania rekrutacyjne: Hilt vs Koin Poniższe pytania regularnie pojawiają się na [rozmowach technicznych z Androida](/technologies/android). Każda odpowiedź jest zwięzła i koncentruje się na tym, czego oczekuje osoba prowadząca rekrutację. **Pytanie: Czym różni się wstrzykiwanie zależności w czasie kompilacji od wstrzykiwania w runtime?** DI w czasie kompilacji (Hilt/Dagger) generuje kod wstrzykiwania podczas budowania projektu. Kompilator waliduje cały graf zależności, wychwytując brakujące bindingi przed uruchomieniem aplikacji. DI w runtime (Koin) rozwiązuje zależności w momencie ich pierwszego żądania, wykorzystując wzorzec rejestru usług. DI kompilacyjne zapewnia szybszy start aplikacji kosztem wolniejszych buildów; DI runtime eliminuje narzut na budowanie, ale odracza wykrywanie błędów. **Pytanie: Jakie zakresy komponentów definiuje Hilt i jak mapują się na cykl życia Androida?** `SingletonComponent` istnieje przez cały czas życia aplikacji. `ActivityRetainedComponent` przeżywa zmiany konfiguracji. `ViewModelComponent` jest powiązany z cyklem życia ViewModel. `ActivityComponent`, `FragmentComponent` i `ViewComponent` odpowiadają cyklom życia swoich właścicieli w hierarchii Android. Hierarchię tę można rozszerzać o niestandardowe zakresy. **Pytanie: Jak Koin obsługuje wstrzykiwanie ViewModel w Jetpack Compose?** Koin udostępnia `koinViewModel()` jako funkcję Composable, która tworzy lub pobiera ViewModel w zakresie najbliższego `ViewModelStoreOwner`. Od wersji 4.2 dostępna jest również funkcja `koinNavViewModel()`, która zakresuje ViewModele do wpisów grafu nawigacji przy korzystaniu z [nawigacji Jetpack Compose](/blog/android/jetpack-compose-interview-questions). **Pytanie: Kiedy Koin będzie lepszym wyborem niż Hilt?** Koin sprawdza się lepiej w projektach KMP (Hilt działa wyłącznie na Androidzie), w małych i średnich aplikacjach, gdzie czas budowania ma większe znaczenie niż czas startu, oraz w zespołach preferujących jawny DSL Kotlina zamiast konfiguracji opartej na adnotacjach. Prototypowanie i projekty proof-of-concept również korzystają z minimalnej konfiguracji Koin. > **Częsty błąd na rozmowach rekrutacyjnych** > > Określanie Koin jako "frameworka wstrzykiwania zależności" jest technicznie nieprecyzyjne. Koin jest lokatorem usług (Service Locator) — zależności są pobierane przez `get()`, a nie dostarczane przez wstrzykiwanie konstruktora. Rekruterzy znający to rozróżnienie oczekują, że kandydat je zasygnalizuje. Hilt/Dagger realizuje rzeczywiste wstrzykiwanie zależności poprzez generowane wywołania konstruktorów. ## Ramka decyzyjna: wybór między Hilt a Koin | Czynnik | Hilt | Koin | |--------|------|------| | Walidacja grafu | Czas kompilacji | Runtime | | Wpływ na czas buildu | Wyższy (generowanie kodu KSP) | Brak | | Koszt startu aplikacji | Bliski zeru | Rośnie proporcjonalnie do rozmiaru grafu | | Krzywa uczenia | Stroma (koncepcje Daggera) | Łagodna (czysty DSL Kotlina) | | Wsparcie KMP | Nie | Tak | | Integracja z Jetpack | Głęboka (oficjalna, Google) | Dobra (społeczność) | | Skalowalność w zespole | Silniejsza (wymuszone zakresy) | Elastyczna (oparta na konwencjach) | | Testowanie | `@TestInstallIn` (walidacja kompilacyjna) | `loadKoinModules` (runtime) | Żaden z frameworków nie jest uniwersalnie lepszy. Wybór zależy od skali projektu, doświadczenia zespołu i docelowych platform. ## Podsumowanie - Hilt 2.57 z KSP zapewnia walidację grafu w czasie kompilacji i niemal zerowy koszt startu aplikacji, co czyni go mocniejszym wyborem dla dużych, jednoplatformowych projektów Android o wysokich wymaganiach niezawodności - Koin 4.2 z mechanizmem lazy modules i silnikiem `CoreResolverV2` zmniejsza dystans wydajnościowy przy starcie, zachowując zerowy wpływ na czas budowania i pełną kompatybilność z KMP - Oba frameworki obsługują architektury wielomodułowe, lecz Hilt wymusza granice zakresów na etapie kompilacji, podczas gdy Koin opiera się na konwencjach zespołu - W kontekście [przygotowania do rozmów rekrutacyjnych z Androida](/technologies/android) zrozumienie kompromisu między walidacją kompilacyjną a runtime'ową oraz umiejętność uzasadnienia wyboru frameworka w konkretnym kontekście projektowym stanowią oczekiwane minimum - Migracja między frameworkami jest procesem nietrywalnym — początkowy wybór powinien uwzględniać długoterminową strategię platformową i kierunek skalowania projektu --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pl/blog/android/android-dependency-injection-hilt-vs-koin