9

我的android项目中有两个模块,app模块和lib模块。

这两个模块都需要 Koin 进行 DI,所以我在 app 模块和 lib 模块中调用startKoinMyApplicationIninKointContentProvider如下所示。

// 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 模块然后调用startKoinin MyApplication,但我不喜欢它。Lib模块可能被其他不使用koin的android项目导入,在这种情况下,我认为调用startKoin更好InitKoinContentProvider

这个问题有什么解决办法吗??谢谢!

4

5 回答 5

5

我找到了受@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

于 2019-05-29T02:03:17.723 回答
4

要在其他项目模块上初始化额外的 koin 模块并且不会出现重复的加载问题(例如按 home,而不是返回活动),请转到您的模块声明文件:

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()
}
于 2019-09-25T16:18:53.577 回答
3

TL;DR在提供覆盖之前加载的模块提供的依赖项时,使用参数设置为的single/factory方法。overridetrue

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 表明您有意通过使用这样的函数override参数来覆盖该依赖项:single

loadKoinModules(module {
    single<Printer>(override = true) { TestPrinter() }
})
于 2020-01-08T07:39:10.350 回答
2

在您的库模块中,用于loadKoinModules()加载特定于模块的 koin 模块。文档

您需要在startKoin()此之前运行,因此内容提供程序的初始化顺序可能有点棘手。

于 2019-05-24T11:24:12.837 回答
1

按照设计startKoin意味着从 Application 类中调用。您可以在库中提供一个参数是否调用startKoin。但我怀疑在库中包含诸如 Koin 之类的东西是一种好习惯。如果应用程序已经包含 Koin,但版本不同怎么办?

于 2019-05-24T09:52:26.460 回答