Hi.
I use Koin (version 2.0.0-beta-1) in my Android application, and it works great 馃檪
Now I am creating an SDK from parts of that application, so I intend to use custom context as described in Koin context isolation
I have an object to store Koin instance
object TcKoinContext {
lateinit var koin: Koin
@Synchronized
fun init(context: Context) {
val koinApp = koinApplication {
androidContext(context)
modules(KoinModules.all)
}
koin = koinApp.koin
}
}
and interface
interface TcKoinComponent : KoinComponent {
override fun getKoin(): Koin = TcKoinContext.koin
}
which I implement in my Application class, activity, fragments and other places where I need to inject dependencies.
Although I thought I done everything correctly, after running the app, I immediately got java.lang.IllegalStateException: KoinApplication has not been started
I investigated it and noticed that
fun ComponentCallbacks.getKoin(): Koin = GlobalContext.get().koin
is always using global context and because Application, Activity, Fragment, etc. implements ComponentCallbacks it never uses my instance of Koin from implemented TcKoinComponent.
So I changed imports from org.koin.android.ext.android.inject to org.koin.core.inject and it helped because this version fo inject is using KoinComponent.getKoin() and not ComponentCallbacks.getKoin()
Now I have a problem with by viewModel()
java.lang.IllegalStateException: KoinApplication has not been started
at org.koin.core.context.GlobalContext.get(GlobalContext.kt:37)
at org.koin.core.KoinComponent$DefaultImpls.getKoin(KoinComponent.kt:32)
at org.koin.androidx.viewmodel.ViewModelResolutionKt$makeViewModelProvider$1.getKoin(ViewModelResolution.kt:42)
at org.koin.androidx.viewmodel.ViewModelResolutionKt$makeViewModelProvider$1.create(ViewModelResolution.kt:44)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:135)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:103)
at org.koin.androidx.viewmodel.ViewModelResolutionKt.getInstance(ViewModelResolution.kt:22)
at org.koin.androidx.viewmodel.ViewModelResolutionKt.resolveViewModelInstance(ViewModelResolution.kt:16)
I think there is a bug in makeViewModelProvider function:
private fun <T : ViewModel> makeViewModelProvider(
vmStore: ViewModelStore,
parameters: ViewModelParameters<T>
): ViewModelProvider {
return ViewModelProvider(
vmStore,
object : ViewModelProvider.Factory, KoinComponent {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return getKoin().get(parameters.clazz, parameters.name, null, parameters.parameters)
}
})
}
It creates anonymous object which implements KoinComponent with default implementaion of getKoin() method which uses Global context and that it is source of this crash. I think it should use activity/fragment (implementing custom KoinComponent) as source of Koin instance.
So instead of object implementing KoinComponent, method create should probalby use fun LifecycleOwner.getKoin() = (this as ComponentCallbacks).getKoin(). But is uses getKoin() from ComponentCallbacks and not from KoinComponent so it won't work with custom context from my TcKoinComponent anyway 馃檨
I hope it will be helpful 馃檪
Besides the problem with makeViewModelProvider method, it would be great if fun ComponentCallbacks.getKoin() could use KoinComponent.getKoin() so the same org.koin.android.ext.android.inject extension method can be used with Global and custom context.
remind me this proposal: https://github.com/InsertKoinIO/koin/pull/341
Yeah context isolation is not enough on this viewmodel side.
For Android globally, you should rewrite a custom KoinComponent to resuse get/inject with your instance and avoid using the API that uses Global context
For Android globally, you should rewrite a custom KoinComponent to resuse get/inject with your instance and avoid using the API that uses Global context
Can you explain what do you mean by that because I thought that implementing custom KoinComponent interface in activities, fragments, etc. will be enough to use custom context on Android? (and it works that way although, as I wrote in my first comment, you have to remember to use core version of get/inject extension methods which is a bit confusing).
@pawelmarchewka check the last version of Koin( has been fixed in beta-3). We better handle Custom KoinComponent & custom Koin instances. You can use directly TcKoinComponent
@arnaudgiuliani It works, thanks! 馃檪
@arnaudgiuliani It works. I think you should add this to the documentation too!
Most helpful comment
@pawelmarchewka check the last version of Koin( has been fixed in beta-3). We better handle Custom KoinComponent & custom Koin instances. You can use directly
TcKoinComponentAn example here: https://github.com/InsertKoinIO/koin/blob/master/koin-projects/examples/android-samples/src/main/java/org/koin/sample/android/components/sdk/SDKActivity.kt