I've been updating several KMP samples I have to K...
# koin
j
I've been updating several KMP samples I have to Koin 4.0.0.....has been fine so far but running in to issue for some reason with https://github.com/joreilly/ClimateTraceKMP where now getting
KoinApplication has not been started
starting say Compose for DesktopWeb clients after updating....
this is stack trace
Copy code
Exception in thread "main" java.lang.IllegalStateException: KoinApplication has not been started
	at org.koin.core.context.GlobalContext.get(GlobalContext.kt:36)
	at org.koin.core.context.GlobalContext.loadKoinModules(GlobalContext.kt:70)
	at org.koin.core.context.KoinContext$DefaultImpls.loadKoinModules$default(KoinContext.kt:58)
	at org.koin.core.context.DefaultContextExtKt.loadKoinModules(DefaultContextExt.kt:50)
	at dev.johnoreilly.climatetrace.di.KoinKt.commonModule$lambda$8(Koin.kt:34)
and difference I think in this project is call to
loadKoinModules
in following
Copy code
fun commonModule(enableNetworkLogs: Boolean = false) = module {
    single { createJson() }
    single { createHttpClient(get(), enableNetworkLogs = enableNetworkLogs) }
    single { ClimateTraceApi(get()) }
    single { CountryListViewModel() }
    single { CountryDetailsViewModel() }
    single { ClimateTraceRepository(get(), get()) }
    loadKoinModules(dataModule())
}
@xxfast I think that was needed due way
kstore
was setup? I tried approach I used in other projects where I used something like following and seem to run in to other (runtime) isssues
Copy code
startKoin {
        appDeclaration()
        modules(commonModule(enableNetworkLogs = enableNetworkLogs), dataModule())
    }
πŸ‘€ 1
p
if you use KoinApplication for desktop or web in KM they change usage :
KoinApplication(application = { modules(appModule, platformModule, databaseModule, viewModelModule) }) {
a
do you use KoinApplication on your non android flavour?
j
yeah, using following for Compose for Desktop and Web clients
Copy code
@Composable
fun App() {
    KoinApplication(application = {
        modules(commonModule())
    }) {
        MaterialTheme {
            Navigator(screen = ClimateTraceScreen())
        }
    }
}
a
ok, and when do you get those errors?
j
When I updated to 4.0
Happens then when I run desktop or web client
p
try to replace
loadKoinModules(dataModule())
by
includes(dataModule)
x
kstore instances needs to be setup for each target platform, i think i've done something like this in the past
Copy code
val application = { 
    modules(dataModule)
}

expect val dataModule: Module

// on wasmJsMain / jsMain
actual val dataModule: Module get() = module { 
  single<KStore<List<Country>>{ storeOf(key = "countries", default = emptyList()) }
}
And yeah, looks like i might've used the wrong koin api to load different modules
πŸ‘ 1
a
yeah, why do you load modules on fly with
loadKoinModules
?
x
yup this doesn't need to be done on the fly - we should be able to just use
includes()
a
yes
j
hmm, get past that using
includes
but run in to some other runtime error then....I'll keep digging
same error as before but happening at different point
Copy code
java.lang.IllegalStateException: KoinApplication has not been started
	at org.koin.core.context.GlobalContext.get(GlobalContext.kt:36)
	at org.koin.core.component.KoinComponent$DefaultImpls.getKoin(KoinComponent.kt:33)
	at dev.johnoreilly.climatetrace.viewmodel.CountryListViewModel.getKoin(CountryListViewModel.kt:21)
this is for
Copy code
open class CountryListViewModel : ViewModel(), KoinComponent {
    private val climateTraceRepository: ClimateTraceRepository by inject()
Could likely be something wrong I have in my setup
so, not much code involved here... App.kt
Copy code
fun App() {
    KoinApplication(application = {
        modules(commonModule())
    }) {
        MaterialTheme {
            Navigator(screen = ClimateTraceScreen())
        }
    }
}
ClimateTraceScreen.kt
Copy code
class ClimateTraceScreen: Screen {
    @Composable
    override fun Content() {
        val countryListViewModel = koinInject<CountryListViewModel>()
        val countryListViewState by countryListViewModel.viewState.collectAsState()
CountryListViewModel.kt
Copy code
open class CountryListViewModel : ViewModel(), KoinComponent {
    private val climateTraceRepository: ClimateTraceRepository by inject()
Koin.kt
Copy code
fun commonModule(enableNetworkLogs: Boolean = false) = module {
    single { createJson() }
    single { createHttpClient(get(), enableNetworkLogs = enableNetworkLogs) }
    single { ClimateTraceApi(get()) }
    single { CountryListViewModel() }
    single { CountryDetailsViewModel() }
    single { ClimateTraceRepository(get(), get()) }
    includes(dataModule())
}
If I don't use
KoinComponent
then it works (but then have issues in iOS client) where
CountryListViewModel
is instantiated directly atm
a
@John O'Reilly do you have a branch that I can checkout?
j
yeah, I just pushed changes to update to Koin 4 to https://github.com/joreilly/ClimateTraceKMP/pull/new/koin_4
as well as the version change it also updates to using
includes
instead of
loadKoinModules
that was used before ....that gets past initial issue we had but then run in to the other one mentioned above that seems related to use of
KoinComponent
You can reproduce then by running say Compose for Desktop app
πŸ‘ 1
a
I'll take a look
@John O'Reilly I just need to launch the main app entry, no?
j
if you go to
main.kt
in
desktopMain
you can run
main
there from IDE
are hit run from here
are u able to reproduce the error there?
a
didn't had time yet
long week 😭
j
there's absolutely no rush from my perspective....was more just in case this was useful for reproducing an issue
a
for sure πŸ‘
j
@arnaud.giuliani just curious if you found any issue that time.....no worries if not, can keep earlier version for now in that project
a
not yet. Was flushing things for Koin Annotations. Taking that on my stack πŸ‘
πŸ‘ 1
any way to see the logs ?πŸ˜… ... hitting run & got the desktop window
but else I don't see outputs #noob
image.png
j
that's with Koin 4?
a
yes the branch with koin_4
j
hmm, trying to remember if anything meaningful was logged....just that it worked if I updated
CountryListViewModel
to not use
KoinComponent
....and injected dependency through constructor instead
Copy code
open class CountryListViewModel(val climateTraceRepository: ClimateTraceRepository) : ViewModel() { //} KoinComponent {
    //private val climateTraceRepository: ClimateTraceRepository by inject()
thought I had been seeing
KoinApplication has not been started
somewhere before....
think this must have been where I saw that error
a
ok, good to know πŸ‘
just a question here, why
ClimateTraceRepository
is not in constructor? I see a race condition here about it being in by inject delegate field
surely a problem in
KoinApplication
composable that don't register well the default context here πŸ€”
be just to be sure why you use
KoinComponent
here
j
probably can find other way but right now it's because that class is created directly in Swift
a
ok, I get it
it's shared on iOS
I've spotted the problem. KoinApplication creates a local isntance of Koin, which is not attached to global context (issue here). Then, the use of `by inject()`triggers the global context, that is not set.
πŸ™Œ 1
I will do a fix πŸš‘
j
nice!
a
that was that πŸ’ͺ
got the app running. Still testing side effects, but should be included in 4.0.1
j
that's great
Just to confirm that this is working with 4.0.1-Beta1 (updated in gh now)
πŸ”₯ 1
koinscroll 1
a
Thanks. Not yet had time to come back on sharing native parts pattern. Still in my TODO stack ^^