以下是代码
自定义注释类:
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class CtxMain
@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class MyScope
成分:
@MyScope
@Component(modules = [ToastMakerModule::class,ActionsModule::class])
interface ActionsComponent {
fun injectIntoMain(activity: MainActivity)
}
模块(为每个模块制作单独的文件):
@Module
class ActionsModule(private var context: Context) {
@Provides
@CtxMain
fun providesContext():Context{
return context
}
@Provides
fun providesSharedPrefs(@CtxMain context: Context): SharedPreferences{
return context.getSharedPreferences("PreferencesFile",Context.MODE_PRIVATE)
}
}
@Module
class ToastMakerModule {
@Provides
fun provideToastMaker(@CtxMain context: Context): ToastMaker{
return ToastMaker(context)
}
}
型号:
@MyScope
class ToastMaker @Inject constructor(@CtxMain private val context:Context) {
fun showToast(){
Toast.makeText(context,"This is a Toast",Toast.LENGTH_SHORT).show()
}
}
主要活动:
class MainActivity : AppCompatActivity() {
@Inject
lateinit var toastMaker: ToastMaker
@Inject
lateinit var toastMaker2: ToastMaker
@Inject
lateinit var sharedPreferences: SharedPreferences
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
DaggerActionsComponent.builder()
.actionsModule(ActionsModule(this))
.build()
.injectIntoMain(this)
toastMaker.showToast()
}
}
运行此代码后,由于 @MyScope 注释,expexted 输出是 toastMaker 和 toastMaker2 应该指向同一个对象,但它们甚至不强硬,ToastMaker 类已用 @MyScope 注释,但仍然为每个创建不同的对象(不同的对象) hashcodes),但修改代码后(删除 ToastMaker 的提供程序),即
修改ToastMakerModule(评论提供者)
@Module
class ToastMakerModule {
// @Provides
// fun provideToastMaker(@CtxMain context: Context): ToastMaker{
// Log.d("#D","Provider de ToastMaker")
// return ToastMaker(context)
// }
}
现在,当字段注入来自 ToastMaker 类本身时,toastMaker 和 toastMaker2 都指向同一个对象(相同的哈希码),我在这里缺少什么?为什么提供者方法不返回相同的实例,甚至用 @MyScope 标记。我知道我们可以使用 @MyScope 注释来标记提供程序方法,以使提供程序方法返回相同的实例,但这不应该起作用,因为 ToastMaker 类是用 @MyScope 注释的。当提供者方法被删除时,它工作正常,为什么?
因为您为 Dagger 提供了
@Provides
方法,所以它将使用该方法并完全忽略 @Inject
带注释的构造函数以及您在类中列出的任何范围。
正如 Dagger 维护者 Brad Corso 在 google/dagger#3361 中提到的“单例在注入应用程序时会被初始化多次”(强调我的):
但是,即使您实际的
类确实具有SubsManager
带注释的构造函数,您仍然应该验证它不是通过模块提供的,因为通过模块提供的 绑定可以隐式覆盖通过@Inject
带注释提供的绑定构造函数。@Inject
要理解此行为,将带
@Inject
注释的构造函数和类范围注释视为单个定义会很有帮助,就像 @Provides
方法及其范围注释是单个定义一样。 Dagger 并没有尝试合并这两个定义(使用类注释定义中的范围和 @Provides 方法定义中的实现),而是只是观察无范围 @Provides 方法定义并完全覆盖类注释定义。
Dagger 的行为就好像您故意尝试覆盖 ToastMaker 上的作用域以使其无作用域 - 这是一个特别合理的假设,因为您可以自定义每个 Dagger 组件的模块集,但您只能准确定义可能可重用的 ToastMaker 类一次。如果您需要重写类,包括直接在类上定义的作用域,那么模块上的
@Provides
方法是您的自然选择,并且您绝对不希望将类上的作用域定义合并到模块重写中。
要解决此问题,您需要删除
@Provides
方法(以便 @Inject
构造函数和作用域保持在一起),或者在 @MyScope
方法上添加适当的 @Provides
注释。