Open YanneckReiss opened 8 months ago
I just realized a drawback with this approach. It only works for constructor injected parameters. When one uses the KoinComponent
for field injection and the respective class needs access to that dependency in the context of that preview (for example at class initialization) the isolated context we defined in the preview wouldn't apply because in the KoinComponent we rely on the Koin GlobalContext
.. therefore using field injection with this approach leads to another exception:
java.lang.IllegalStateException: KoinApplication has not been started at org.koin.core.context.GlobalContext.get(GlobalContext.kt:36)
To visualize it, the following example with constructor injection works:
class TestClass(
private val myInjectedClass: MyInjectedClass
)
While this example won't work because we eagerly inject the MyInjectedClass and therefore access the GlobalContext
under the hood:
class TestClass: KoinComponent {
private val myInjectedClass: MyInjectedClass = get()
}
The Koin documentation suggests to define a custom KoinComponent
but that wouldn't work for this case because we dynamically create a custom context for each preview. @arnaudgiuliani therefore maybe this pull request is obsolete or maybe you have an idea how to workaround this problem?
we may need to investigate more to help cover the general case, and see the edge cases around 🤔 Let's keep it as a base of suggestion. You can also restart a PR if you want
can be moved into koin-compose-viewmodel
Otherwise idea sounds good. We need to tag it Experimental to get feedback
Problem description this pull request aims to resolve
When we have a single composable in Android Jetpack Compose that depends on injecting some definitions, we can easily use the
KoinApplication
composable, like currently suggested in the Koin documentation for Compose Previews.However, it's often the case that we want to define multiple compose previews with different use cases states of our composable. Unfortunately, when we have two or more compose previews in a single file, using the
KoinApplication
composable in both of them leads to aorg.koin.core.error.KoinAppAlreadyStartedException
because the first startedKoinApplication
also lives in the second compose preview.The problem here is that we often want to provide a different set of definitions (a different list of modules), or simply can't guarantee which of the compose previews will build first, and therefore don't know if we need to start another
KoinApplication
or just can use theKoinContext
composable to provide aKoinContext
. Another solution would be to manually create an isolated context for each of the compose previews and supply it to aKoinApplication
, which would introduce a lot of boilerplate code.To showcase this problem at a practical example I created a small sample repository.
Description of my proposal
My solution for this problem is contained in this pull request. It should make the life easier for all developers who want to create compose previews for composables that rely on Koin.
If we come back to the mentioned example repository and take a look at the
ExampleView
instead of the following which throws theorg.koin.core.error.KoinAppAlreadyStartedException
:we can simply replace the code with the following and don't need to worry about managing a compose preview (file) wide Koin context: