Dagger2 自定义作用域:在模块中使用提供程序方法时,@Inject 构造函数注入中看不到自定义作用域吗?

问题描述 投票:0回答:1

以下是代码

自定义注释类:

@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 注释的。当提供者方法被删除时,它工作正常,为什么?

android kotlin scope dagger-2 dagger
1个回答
0
投票

因为您为 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
注释。

© www.soinside.com 2019 - 2024. All rights reserved.