在Github上的Injekt文档中,它说明了作用域的存在,但尚不清楚如何使用它们为每个Android Activity 创建本地作用域,这些 Activity 具有自己的工厂和实例,但也可以使用父作用域中的某些作用域。Injekt
变量似乎是全局作用域,我看到了InjektScope
和InjektScopeMain
,但没有有关如何使用它们或如何链接到父作用域的示例。我看到的唯一方法是创建单独的InjektScope
实例并调用它们,或者将Injekt
称为全局范围。这有效,但笨拙。
没有明显的链接,嵌套,委托(delegate)或继承的方法。
是否支持此功能?
注意:这个问题是作者故意写并回答的(Self-Answered Questions),因此SO中常见的Injekt + Kotlin主题的惯用答案。也欢迎其他答案,还有其他样式的操作方法!披露,我是Injekt库的作者。
最佳答案
更新:,现在记录在Injekt README中
通过在范围之间委派工厂来支持它。首先,一些背景:
Injekt允许将实例的作用域手动划分到单独的Injekt注册表中。可以通过Injekt
变量获得的全局注册表只是为您预先创建的一个作用域。您还可以创建新的:
val myLocalScope: InjektScope = InjektScope(DefaultRegistrar())
这样就形成了一个独立的范围,该范围与全局范围或其他范围无关。
但是,然后您可以通过在新作用域中创建将某些实例创建委托(delegate)给另一个作用域的工厂来链接作用域。例如,上面提到的
myLocalScope
可以将某些工厂委托(delegate)给Injekt
全局范围:// delegate some factories to global Injekt instance
myLocalScope.addSingletonFactory { Injekt.get<SomeSingletonClass>() }
myLocalScope.addFactory { Injekt.get<SomeMultiValueClass>() }
当委托(delegate)这样的工厂时,任何多值实例都不会被任何作用域缓存,因为这些工厂在每次调用时都会创建新的实例。对于单例和键控工厂,将缓存对象,并且在其生命周期内所请求的任何实例的本地和委托(delegate)范围中都将存在对这些对象的引用。
您也可以只使用多个作用域,而无需链接或委派。从本地范围获取某些实例,从全局范围获取其他实例。但是,您必须独立使用每个作用域,并且在不希望使用时请小心使用
Injekt
全局变量。如果您在本地范围内需要通用工厂,则可以轻松创建
InjektScope
的后代,并在其构造期间对其进行注册。class MyActivityScope: InjektScope(DefaultRegistrar()) {
init {
// override with local value
addSingletonFactory { SomeSingletonClass() }
// import other registrations from defined modules
importModule(OtherModuleWithPrepackagedInjektions)
// delegate to global scope:
addSingletonFactory { Injekt.get<SomeOtherSingleton>() }
}
}
// then in each place you want a local scope
val localScope = MyActivityScope()
// later use the scope
val singly: SomeSingletonClass = localScope.get()
val other: SomeOtherSingleton = localScope.get()
或者,如果您希望与模块保持一致,则可以使用与
InjektMain
相同的模型来创建InjektScopedMain
的后代,以覆盖fun InjektRegistrar.registerInjectables() { ... }
函数。例如:class MyActivityModule: InjektScopedMain(InjektScope(DefaultRegistrar())) {
override fun InjektRegistrar.registerInjectables() {
// override with local value
addSingletonFactory { NotLazy("Freddy") }
// import other registrations from defined modules
importModule(OtherModuleWithPrepackagedInjektions)
// delegate to global scope:
addSingletonFactory { Injekt.get<SomeOtherSingleton>() }
}
}
// then in each place you want a local scope
val localScope = MyActivityModule().scope
而且,只要在委托(delegate)中使用作用域之前就声明了作用域,您仍然可以使用委托(delegate)属性:
val myProp: SomeClass by localScope.injectValue()
您可以使用
LocalScoped
基类来获取本地版本的injectValue()
和injectLazy()
,以便在注入(inject)成员时更加方便(请参阅code for LocalScoped
)。这样,您的语法将保持一致(请参阅example in tests)。要清除本地范围,请将您对范围的引用删除,它会垃圾回收。没有明确的清除方法。
有关更高级,更自动的作用域链接/委托(delegate)/继承的信息,请参见Injekt Github Issue #31并提供有关此可能的将来功能的注释。
对于让其他类在声明到本地范围的类中被继承时继承相同的本地范围的用例,请参见Injekt Github Issue #32。