在 Kotlin 的 Injekt 库中,如何为每个 Android activity 创建本地作用域?
In the Injekt library for Kotlin, how do I create local scopes such as for each Android activity?
在关于 Github 的 Injekt 文档中,它说范围存在,但不清楚我如何使用它们为每个 Android activity 创建本地范围,有自己的工厂和实例,但也可以使用父作用域中的一些。
Injekt
变量似乎是一个全局范围,我看到了 InjektScope
和 InjektScopeMain
,但没有关于如何使用它们或它们如何使用的示例 link到父范围。我看到的唯一方法是创建单独的 InjektScope
实例并调用它们,或者将 Injekt
作为全局范围调用。这行得通,但是很笨拙。
没有明显的方法来 link、嵌套、委托或继承。
是否支持,如果支持如何支持?
注: 此题是作者(Self-Answered Questions)特意写下并回答的,所以常用Injekt的地道答案+ Kotlin 主题出现在 SO 中。也欢迎其他答案,还有其他样式的方法!披露,我是 Injekt 库的作者。
更新: 现在记录在 Injekt README
范围之间的委托工厂支持它。首先,一些背景:
Injekt 允许手动将实例范围限定到单独的 Injekt 注册表中。通过 Injekt
变量可用的全局注册表只是为您预先创建的一个范围。您也可以创建新的:
val myLocalScope: InjektScope = InjektScope(DefaultRegistrar())
这形成了一个与全局或其他无关的独立范围。
但是您可以 link 通过在新作用域中创建工厂来将一些实例创建委托给另一个作用域。例如上面提到的 myLocalScope
可以将一些工厂委托给 Injekt
全局范围:
// delegate some factories to global Injekt instance
myLocalScope.addSingletonFactory { Injekt.get<SomeSingletonClass>() }
myLocalScope.addFactory { Injekt.get<SomeMultiValueClass>() }
像这样委托工厂时,任何多值实例都不会被任何范围缓存,因为这些工厂在每次调用时都会创建新实例。对于单例和键控工厂,对象被缓存,并且对这些对象的引用将存在于本地和委托范围内,用于在其生命周期内请求的任何实例。
您也可以独立使用多个作用域,而无需 linking 或委派。从本地范围获取一些实例,从全局范围获取其他实例。但是您必须独立使用每个作用域,并小心不要意外使用 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
并且您仍然可以使用委托属性,只要在委托中使用之前声明范围:
val myProp: SomeClass by localScope.injectValue()
您可以使用 LocalScoped
基础 class 来获得 injectValue()
和 injectLazy()
的本地版本,以便在注入成员时更加方便(参见 code for LocalScoped
). This way your syntax stays consistent (see example in tests).
要清除本地作用域,请删除对该作用域的引用,它将垃圾收集掉。没有明确的清除方法。
有关更高级、更自动的作用域 linking / 委派 / 继承,请参阅 Injekt Github Issue #31 并提供有关此未来可能功能的评论。
关于让其他 classes 在注入到 class 声明局部作用域时继承相同的局部作用域的用例,请参阅 Injekt Github Issue #32
在关于 Github 的 Injekt 文档中,它说范围存在,但不清楚我如何使用它们为每个 Android activity 创建本地范围,有自己的工厂和实例,但也可以使用父作用域中的一些。
Injekt
变量似乎是一个全局范围,我看到了 InjektScope
和 InjektScopeMain
,但没有关于如何使用它们或它们如何使用的示例 link到父范围。我看到的唯一方法是创建单独的 InjektScope
实例并调用它们,或者将 Injekt
作为全局范围调用。这行得通,但是很笨拙。
没有明显的方法来 link、嵌套、委托或继承。
是否支持,如果支持如何支持?
注: 此题是作者(Self-Answered Questions)特意写下并回答的,所以常用Injekt的地道答案+ Kotlin 主题出现在 SO 中。也欢迎其他答案,还有其他样式的方法!披露,我是 Injekt 库的作者。
更新: 现在记录在 Injekt README
范围之间的委托工厂支持它。首先,一些背景:
Injekt 允许手动将实例范围限定到单独的 Injekt 注册表中。通过 Injekt
变量可用的全局注册表只是为您预先创建的一个范围。您也可以创建新的:
val myLocalScope: InjektScope = InjektScope(DefaultRegistrar())
这形成了一个与全局或其他无关的独立范围。
但是您可以 link 通过在新作用域中创建工厂来将一些实例创建委托给另一个作用域。例如上面提到的 myLocalScope
可以将一些工厂委托给 Injekt
全局范围:
// delegate some factories to global Injekt instance
myLocalScope.addSingletonFactory { Injekt.get<SomeSingletonClass>() }
myLocalScope.addFactory { Injekt.get<SomeMultiValueClass>() }
像这样委托工厂时,任何多值实例都不会被任何范围缓存,因为这些工厂在每次调用时都会创建新实例。对于单例和键控工厂,对象被缓存,并且对这些对象的引用将存在于本地和委托范围内,用于在其生命周期内请求的任何实例。
您也可以独立使用多个作用域,而无需 linking 或委派。从本地范围获取一些实例,从全局范围获取其他实例。但是您必须独立使用每个作用域,并小心不要意外使用 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
并且您仍然可以使用委托属性,只要在委托中使用之前声明范围:
val myProp: SomeClass by localScope.injectValue()
您可以使用 LocalScoped
基础 class 来获得 injectValue()
和 injectLazy()
的本地版本,以便在注入成员时更加方便(参见 code for LocalScoped
). This way your syntax stays consistent (see example in tests).
要清除本地作用域,请删除对该作用域的引用,它将垃圾收集掉。没有明确的清除方法。
有关更高级、更自动的作用域 linking / 委派 / 继承,请参阅 Injekt Github Issue #31 并提供有关此未来可能功能的评论。
关于让其他 classes 在注入到 class 声明局部作用域时继承相同的局部作用域的用例,请参阅 Injekt Github Issue #32