The following is the code
以下是代码
Custom Annotation classes:
自定义注释类:
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class CtxMain
@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class MyScope
Component:
组件:
@MyScope
@Component(modules = [ToastMakerModule::class,ActionsModule::class])
interface ActionsComponent {
fun injectIntoMain(activity: MainActivity)
}
Modules (Seperate File are made for each module):
模块(每个模块都有单独的文件):
@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)
}
}
Models:
型号:
@MyScope
class ToastMaker @Inject constructor(@CtxMain private val context:Context) {
fun showToast(){
Toast.makeText(context,"This is a Toast",Toast.LENGTH_SHORT).show()
}
}
MainActivity:
MainActivity:
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()
}
}
Upon running this code the expexted ouptut was that due to @MyScope annotation toastMaker and toastMaker2 should point to the same object but they are not even tough the ToastMaker class has been annotated with @MyScope but still different obejcts are created for each (different hashcodes), but upon modifying the code (removing the provider for ToastMaker) i.e.
在运行这段代码时,扩展的结果是由于@MyScope注释toastaker和toastMaker2应该指向相同的对象,但它们甚至不是坚固的,toastaker类已经用@MyScope注释,但仍然为每个对象创建了不同的bejct(不同的散列码),但是在修改代码时(删除toastaker的提供程序),即
Modified ToastMakerModule (commented the provider)
已修改ToastMakerModule(对提供程序进行了注释)
@Module
class ToastMakerModule {
// @Provides
// fun provideToastMaker(@CtxMain context: Context): ToastMaker{
// Log.d("#D","Provider de ToastMaker")
// return ToastMaker(context)
// }
}
Now when the Field Injection is coming from the ToastMaker Class itself, both toastMaker and toastMaker2 point to the same obejct (same hashcode), What am i missing here? why is provider method not returning me the same instance even tough its marked with @MyScope. i know we can mark the provider method with @MyScope annotation to make provider method return the same instance but shouldnt this work because the ToastMaker class is annotated with @MyScope. when provider method is removed its working fine, why?
现在,当字段注入来自ToastMaker类本身时,toastMaker和toastMaker2都指向相同的bejct(相同的散列码),我在这里遗漏了什么?为什么提供者方法不向我返回相同的实例,甚至很难将其标记为@MyScope。我知道我们可以用@MyScope注释来标记提供者方法,以使提供者方法返回相同的实例,但这不应该起作用,因为toastaker类是用@MyScope注释的。当提供程序方法被移除时,它的工作正常,为什么?
更多回答
优秀答案推荐
Because you've offered Dagger a @Provides
method, it will use that and completely ignore the @Inject
-annotated constructor and any scopes you list on the class.
因为您已经为Dagger提供了一个@Provides方法,所以它将使用该方法并完全忽略@Inject注释的构造函数和您在类中列出的任何作用域。
As Dagger maintainer Brad Corso mentions in google/dagger#3361 "Singletons are initilized several times when injected into application" (emphasis mine):
正如Dagger的维护者Brad Corso在Google/Dagger#3361中提到的那样,“单例在注入应用程序时会被初始化几次”(重点是我的):
However, even if your actual SubsManager
class does have an @Inject
-annotated constructor you should still verify it is not provided via a module since bindings provided via a module can implicitly override bindings provided via an @Inject
-annotated constructor.
To understand this behavior, it is helpful to think of the @Inject
-annotated constructor and class scope annotations as a single definition, just like the @Provides
method and its scope annotations are a single definition. Rather than trying to merge the two definitions (using the scope from the class-annotation definition and the implementation from the @Provides method definition), Dagger just observes the scopeless @Provides method definition and entirely overrides the class-annotation definition.
要理解这种行为,将@Inject注释的构造函数和类作用域注释看作单个定义会很有帮助,就像@Provides方法及其作用域注释是单个定义一样。Dagger并没有尝试合并这两个定义(使用来自类注释定义的作用域和来自@Provides方法定义的实现),而只是观察无作用域的@Provides方法定义,并完全覆盖类注释定义。
Dagger behaves as if you are deliberately trying to override the scope on ToastMaker to make it scopeless--which is a particularly reasonable assumption because you can customize your set of modules per Dagger component but you can only define your potentially-reusable ToastMaker class exactly once. If you need to override the class, including scopes defined directly on the class, then a @Provides
method on a module is your natural choice and you absolutely wouldn't want the scope definition on the class to be merged into your module override.
Dagger的行为就像是故意试图覆盖toastaker上的作用域,使其成为无作用域--这是一个特别合理的假设,因为您可以为每个Dagger组件定制一组模块,但您只能定义潜在可重用的toastaker类一次。如果您需要覆盖类,包括直接在类上定义的作用域,那么模块上的@Provides方法是您的自然选择,您绝对不希望将类上的作用域定义合并到模块覆盖中。
To fix this problem, you'll need to either remove the @Provides
method (such that the @Inject
constructor and scope remain together), or add the appropriate @MyScope
annotation onto the @Provides
method.
要解决这个问题,您需要删除@Provides方法(以便@Inject构造函数和作用域保留在一起),或者在@Provides方法上添加适当的@MyScope注释。
更多回答
Thank you very much for such detailed answer. Kudos to you!
非常感谢您如此详细的回答。向你致敬!
我是一名优秀的程序员,十分优秀!