Riippuvuuksien injektointi KMP:ssä Koinilla
Yhdistäkää jaetut moduulit Koinilla monialustaisessa ympäristössä.
Riippuvuuksien injektointi KMP:ssä Koinilla on ilmainen Kotlin Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Kotlin Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Kotlin Academy-kurssilla on yhteensä 4 oppituntia.
Miksi DI:tä käytetään KMP:ssä?
Riippuvuuksien injektointi erottaa komponenttien luomisen niiden käytöstä. KMP:ssä Koin on ensisijainen DI-kehys, koska se on puhdasta Kotlinia ja toimii kohteessa commonMain ilman annotaatioprosessoreita.
// No annotation processing needed — Koin uses lambda DSL
// Add to build.gradle.kts:
// implementation("io.insert-koin:koin-core:3.5.0")
// androidMain: koin-android
// iosMain: no extra dep
fun main() { println("Koin works on all KMP targets") }Koinin moduuli-DSL
Määrittele sidonnat module { }-lohkossa käyttämällä single-, factory- tai scoped-määritystä.
import org.koin.core.module.dsl.*
import org.koin.dsl.*
val appModule = module {
single { HttpClient() } // one instance
single<UserRepository> { RemoteUserRepository(get()) }
factory { GetUserUseCase(get()) } // new instance each time
}Jaettu moduuli kohteessa commonMain
Määrittele jaettu Koin-moduuli kohteessa commonMain. Alustakohtaiset moduulit laajentavat sitä omilla sidonnoillaan.
// commonMain/di/SharedModule.kt
import org.koin.dsl.module
fun sharedModule() = module {
single<UserRepository> { RemoteUserRepository(get()) }
single { GetUserUseCase(get()) }
single { UserViewModel(get()) }
}Alustakohtainen moduuli kohteessa androidMain
Alustakohtaiset moduulit tarjoavat varsinaisen HTTP-moottorin, tietokanta-ajurin ja Android-kohtaiset singletonit.
// androidMain/di/AndroidModule.kt
import io.ktor.client.engine.okhttp.*
import org.koin.dsl.module
fun androidModule() = module {
single { OkHttp.create() } // Ktor engine
single { createHttpClient(get()) }
includes(sharedModule())
}startKoin Android-sovelluksessa
Kutsu startKoin { }-funktiota Androidin Application.onCreate-metodissa. Käytä androidContext(this)-kutsua, jotta konteksti on käytettävissä.
// androidMain:
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
// In Application.onCreate():
startKoin {
androidContext(this@MyApp)
modules(androidModule())
}Koinin käynnistäminen iOS:llä
Kutsu iOS:llä KoinApplication.start()-funktiota Swiftin AppDelegate- tai App-rakenteesta ja välitä sille jaetut Koin-moduulit.
// iosMain/KoinInit.kt:
import org.koin.core.context.startKoin
fun initKoin() {
startKoin {
modules(iosModule())
}
}
// Swift: KoinInitKt.doInitKoin() in AppDelegateRiippuvuuksien ratkaiseminen
Käytä commonMain-kohteen ViewModel- tai käyttötapausluokissa get()-funktiota moduulin sisällä tai inject()- ja getKoin().get()-funktioita kutsukohdissa.
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class UserViewModel : KoinComponent {
private val getUser: GetUserUseCase by inject()
fun load(id: String) = runBlocking { getUser(id) }
}Koinin scopet ViewModel-luokille
Käytä Android-moduulissa viewModel { }-määritystä Androidin ViewModel-luokille tai alustasta riippumatonta factory { }-määritystä jaetuille ViewModel-luokille.
// androidMain (with koin-android):
import org.koin.androidx.viewmodel.dsl.viewModel
val androidVmModule = module {
viewModel { UserViewModel(get()) }
}
// In Compose:
// val vm: UserViewModel = koinViewModel()Testaus Koinilla
Käytä testien alustuksessa startKoin-funktiota ja testimoduulia, joka korvaa todelliset riippuvuudet valetoteutuksilla.
import org.koin.core.context.startKoin
import org.koin.core.context.stopKoin
import org.koin.dsl.module
class UserViewModelTest {
@BeforeTest fun setup() {
startKoin { modules(module {
single<UserRepository> { FakeUserRepository() }
single { GetUserUseCase(get()) }
})}
}
@AfterTest fun teardown() = stopKoin()
}Single vs Factory vs Scoped
single: yksi instanssi sovelluksen koko elinkaaren ajan. factory: uusi instanssi jokaista get()-kutsua kohden. scoped: yksi instanssi Koin-scopea kohden (esimerkiksi näyttökohtainen scope).
import org.koin.dsl.module
val lifetimeModule = module {
single { Database() } // shared, one instance
factory { Analytics() } // new on each get()
scope<ScreenScope> {
scoped { ScreenViewModel() } // one per screen lifecycle
}
}Koin vs manuaalinen DI vs Hilt
Koin: monialustainen, ei KSP:tä tai KAPT:tä, ajonaikainen DI. Hilt: vain Androidille, käännösaikainen ja annotaatioihin perustuva. Manuaalinen DI: täysi hallinta ilman kehyksen aiheuttamaa ylimääräistä kuormaa. KMP-projekteissa jakamiseen käytetään Koinia.
fun main() {
// Koin : commonMain, runtime, lambda DSL
// Hilt : androidMain only, compile-time
// Manual: no framework, explicit wiring in factory/module files
println("Choose Koin for KMP; Hilt for Android-only projects")
}Laiska injektointi by inject()-määrityksellä
by inject() ratkaisee riippuvuuden laiskasti ensimmäisen käyttökerran yhteydessä — tämä on hyödyllistä luokissa, jotka toteuttavat KoinComponent-rajapinnan.
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class AppService : KoinComponent {
private val repo: UserRepository by inject() // resolved on first use
fun doWork() = println(repo.javaClass.simpleName)
}Pikakysymys
Mikä Koin-scope luo uuden instanssin joka kerta, kun get()-funktiota kutsutaan?
Kertaus
Koin käyttää lambda-DSL:ää ilman annotaatioiden käsittelyä — se sopii erinomaisesti KMP:hen. Määrittele jaetut moduulit kohteessa commonMain ja alustakohtaiset moduulit alustojen lähdekoodijoukoissa. Käytä single-määritystä singleton-instansseille, factory-määritystä uusille instansseille ja by inject()-määritystä laiskaan ratkaisemiseen.
Opi Kotlin tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 51
- Oppitunnit
- 203
Usein kysytyt kysymykset
Onko oppitunti ”Riippuvuuksien injektointi KMP:ssä Koinilla” ilmainen?
Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Kotlin Academy-oppimispolun 3 oppituntia, myös oppitunnin “Riippuvuuksien injektointi KMP:ssä Koinilla”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Kotlin Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Riippuvuuksien injektointi KMP:ssä Koinilla”?
Yhdistäkää jaetut moduulit Koinilla monialustaisessa ympäristössä. Harjoittelet Kotlin Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Kotlin Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Kotlin Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.
Kuinka kauan ”Riippuvuuksien injektointi KMP:ssä Koinilla”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Kotlin Academy-oppitunnilla?
Kyllä. Jokainen Kotlin Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- KMP-projektin rakenne: commonMain, androidMain, iosMain
- expect/actual-mekanismi alustakohtaisille rajapinnoille
- Repository- ja Use Case -kerrosten jakaminen
- Riippuvuuksien injektointi KMP:ssä Koinilla