Kotlin Academy · Oppitunti

Riippuvuuksien injektointi KMP:ssä Koinilla

Yhdistäkää jaetut moduulit Koinilla monialustaisessa ympäristössä.

Oppitunti 4/414 vaihetta

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 AppDelegate

Riippuvuuksien 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.

Aloita maksutta

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

  1. KMP-projektin rakenne: commonMain, androidMain, iosMain
  2. expect/actual-mekanismi alustakohtaisille rajapinnoille
  3. Repository- ja Use Case -kerrosten jakaminen
  4. Riippuvuuksien injektointi KMP:ssä Koinilla
← Takaisin: Kotlin Academy