[英]How to use Koin in multiple module?
我的android项目中有两个模块,app模块和lib模块。
这两个模块都需要 Koin 进行 DI,所以我在 app 模块中调用MyApplication
startKoin
中的IninKointContentProvider
,在 lib 模块中调用 IninKointContentProvider,如下所示。
// app module
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin(this, modules1)
}
}
// lib module
class InitKoinContentProvider : ContentProvider() {
override fun onCreate(): Boolean {
startKoin(context.applicationContext, modules2)
return true
}
}
然后应用程序崩溃并显示此消息
Caused by: org.koin.error.BeanOverrideException: Try to override definition with Single [class='android.content.Context'], but override is not allowed. Use 'override' option in your definition or module.
我想startKoin
只能调用一次。
我找到的解决方案是合并两个 koin 模块,然后在MyApplication
中调用startKoin
,但我不喜欢它。 Lib 模块可能被其他不使用 koin 的 android 项目导入,在这种情况下,我认为在InitKoinContentProvider
中调用startKoin
更好。
这个问题有什么解决办法吗?? 谢谢!
我找到了受@laalto 回答启发的最佳解决方案,谢谢!
升级到koin 2.0,然后使用KoinApplication和自定义的KoinComponent来创建一个隔离的koin上下文,它可以让lib模块使用koin而无需app模块进行任何初始化调用,仍然在ContentProvider中启动koin。 整个代码可能如下所示。
// app module
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@MyApplication)
modules(module{
viewModel { MainViewModel() }
})
}
}
}
class MainActivity: AppCompactActivity() {
private val viewModel: MainViewModel by viewModel()
}
// lib module
internal object MyKoinContext {
lateinit var koinApplication: KoinApplication
}
interface MyKoinComponent : KoinComponent {
override fun getKoin(): Koin {
return MyKoinContext.koinApplication.koin
}
}
class InitKoinContentProvider : ContentProvider() {
override fun onCreate(): Boolean {
MyKoinContext.koinApplication = koinApplication {
androidContext(context.applicationContext)
modules(module{
viewModel { FooViewModel() }
})
}
return true
}
}
class FooActivity: AppCompactActivity(), MyKoinComponent {
private val viewModel: FooViewModel by viewModel()
}
参考: https : //insert-koin.io/docs/2.0/documentation/reference/index.html#_koin_context_isolation
要在其他项目模块上初始化额外的 koin 模块并且不会出现重复的加载问题(例如按下主页,而不是返回活动),请转到您的模块声明文件:
val myModule = module {
single { MyRepository(get()) }
viewModel { MyViewModel(get()) }
}
private val loadKoinModules by lazy {
loadKoinModules(myModule)
}
fun inject() = loadKoinModules
那么在你看来:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
inject()
}
TL;DR 在提供覆盖之前加载的模块提供的依赖项时,使用override
参数设置为true
single/factory
方法。
single<Manager>(override = true) { TestManager() }
当我为了 UI 测试目的而尝试覆盖其中一个依赖项时,我遇到了类似的问题。 当我在Application.onCreate()
设置时:
startKoin {
module {
single { Printer() }
}
}
然后在测试方法before
:
loadKoinModules(module {
single<Printer> { TestPrinter() }
})
我在测试期间收到运行时异常: org.koin.core.error.DefinitionOverrideException: Already existing definition or try to override an existing one
解决方案是向 Koin 展示您有意通过使用single
函数的override
参数来override
该依赖项,如下所示:
loadKoinModules(module {
single<Printer>(override = true) { TestPrinter() }
})
在您的库模块中,使用loadKoinModules()
加载特定于模块的 koin 模块。 文档。
您需要在此之前运行startKoin()
,因此内容提供程序的初始化顺序可能有点棘手。
根据设计, startKoin
旨在从 Application 类中调用。 你可以在lib中提供一个参数是否调用startKoin
。 但我怀疑在 libs 中包含 Koin 之类的东西是一种很好的做法。 如果应用程序已经包含 Koin,但版本不同怎么办?
这种方式对我来说很完美:
@KoinExperimentalAPI
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
initKoin()
}
private fun initKoin() {
startKoin {
androidLogger()
androidContext(this@MainApplication)
}
loadKoinModules(
myFeatureModule
)
}
}
并像往常一样在您的功能中定义您的模块:
val myFeatureModule = module {
factory<...> { ...() }
single { ...() }
viewModel { ...(get() }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.