Reputation: 718
Recently I published a library with koin; when I used this library in my own application, everything is ok because I don't use Koin in my application, but if I startKoin
in my application and the library both, the app crashes!.
Is there any way to use koin in application and library same? how can I call startKoin
in my library without facing any problem in apps that used koin and called startKoin
?
org.koin.core.error.KoinAppAlreadyStartedException: A Koin Application has already been started
Upvotes: 5
Views: 1722
Reputation: 152787
I don't think a library should have any dependency injection framework in it, with the exception if the library is only used by your own projects. Choosing a dependency injection framework is an application-wide architectural decision and a library should not force any specific choice for users of the library.
My suggestion is to remove koin from your library completely.
The crash is just a symptom of the design problem: a library making application-wide decisions. Removing koin from the library also gets rid of the crash.
Conceptually you can use dependency injection in your library. For example, have dependencies as constructor arguments and allow callers to use any DI framework of their choosing (or none at all) to wire up the dependencies.
Edit: Yes, a custom koin component can be used to isolate koin in a way that is mostly internal to the library. There are still hidden dependencies that affect the top level application, for example gradle dependency resolution can update koin to an incompatible version - there have been breaking changes in semantically versioned patch/minor updates in koin's past and there can be more in the future.
I consider the architectural advice still pretty much valid: a generic, reusable library should not come with heavy dependencies such as a DI tool. And not having koin in the library is one way to solve the original problem.
Upvotes: 2
Reputation: 718
After some research, I found that I should use a custom KoinComponent
.
Based on the documentation:
For SDK Makers, you can also work with Koin in a non global way: use Koin for the DI of your library and avoid any conflict by people using your library and Koin by isolating your context
// create a KoinApplication
val myApp = koinApplication {
// declare used modules
modules(coffeeAppModule)
}
And keep myApp
in a object:
// Get a Context for your Koin instance
object MyKoinContext {
var koinApp : KoinApplication? = null
}
// Register the Koin context
MyKoinContext.koinApp = KoinApp
and then :
interface CustomKoinComponent : KoinComponent {
// Override default Koin instance, intially target on GlobalContext to yours
override fun getKoin(): Koin = MyKoinContext?.koinApp.koin
}
And now, you register your context and run your own isolated Koin components:
MyKoinContext.koinApp = myApp
class ACustomKoinComponent : CustomKoinComponent(){
// inject & get will target MyKoinContext
}
Upvotes: 4