首页 > 解决方案 > 带有自定义限定符的 Dagger 多重绑定

问题描述

我调用了以下接口,该接口SettingHandler负责处理与 Android 应用程序中的特定设置相关的事件。

interface SettingHandler {

    fun onHandleEvent(event: SettingEvent)

    fun candleHandleEvent(event: SettingEvent): Boolean

    fun getSettingId(): SettingId

}

然后假设我有以下 Dagger 模块:

@Module
object SettingsModule {

    @Provides
    fun provideSettingPresenter(
        view: SettingsContract.View,
        settingHandlers: Set<@JvmSuppressWildcards SettingHandler>
    ): SettingsPresenter {
        //
    }

    @Provides
    @IntoSet
    fun provideSettingHandlerA(
        dependencyA: A,
        dependencyB: B
    ): SettingHandler {
        // 
    }

    @Provides
    @IntoSet
    fun provideSettingHandlerB(
        settingHandlerC: Provider<SettingHandler>
    ): SettingHandler {
        //
    }

    @Provides
    @IntoSet
    fun provideSettingHandlerC(
        settingHandlerB: Provider<SettingHandler>
    ): SettingHandler {
        //
    }

}

如您所见,这里没有什么特别之处,只需要使用SettingHandlerBSettingHandlerCprovider 方法即可。它们都相互依赖,所以我决定使用 Dagger 提供的 Provider 类来解决这种循环依赖。由于我需要一个设置处理程序的具体实现(用于SettingHandlerCSettingHandlerB),我现在需要区分它们。这就是注释发挥作用的地方。我创建了以下限定符注释来区分不同的实现。SettingHandlerBSettingHandlerC@Qualifier

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER)
annotation class SettingHandlerType(val id: SettingId)

SettingId基本上是一个包含所有可能设置常量的枚举。所以现在我SettingHandler的 s 模块如下所示:

@Module
object SettingsModule {

    @Provides
    fun provideSettingPresenter(
        view: SettingsContract.View,
        settingHandlers: Set<@JvmSuppressWildcards SettingHandler>
    ): SettingsPresenter {
        //
    }

    @Provides
    @SettingHandlerType(SettingId.A)
    fun provideSettingHandlerA(
        dependencyA: A,
        dependencyB: B
    ): SettingHandler {
        //
    }

    @Provides
    @SettingHandlerType(SettingId.B)
    fun provideSettingHandlerB(
        @SettingHandlerType(SettingId.C)
        settingHandlerC: Provider<SettingHandler>
    ): SettingHandler {
        //
    }

    @Provides
    @SettingHandlerType(SettingId.C)
    fun provideSettingHandlerC(
        @SettingHandlerType(SettingId.B)
        settingHandlerB: Provider<SettingHandler>
    ): SettingHandler {
        //
    }

}

问题来了。多重绑定现在不起作用,因为我的所有SettingHandlers 都带有@SettingHandlerType注释,并且我注入的 SetSettingsPresenter也需要注释。但是,使用例如注释@SettingHandlerType(SettingId.A)将不起作用,因为在这种情况下, Set 将仅包含具有该特定限定符的设置处理程序(SettingHandlerA在本例中为 )。我如何使用多重绑定构造一个 Set 数据结构,因为我真的不想提供另一个提供者方法来自己构造它?

任何帮助将非常感激。提前致谢。

标签: androiddependency-injectiondagger-2daggermultibinding

解决方案


您需要两种不同类型的数据: type 的单个处理程序@SettingHandlerType(/*...*/) SettingHandler和一组 type Set<SettingHandler>。我认为最好的方法是让每个定义都带有一个@Binds @IntoSet补充。

@Binds @IntoSet abstract fun bindSettingHandlerA(
    @SettingHandlerType(SettingId.A) handler: SettingHandler): SettingHandler

不幸的是,由于您已在 Kotlin 中将其定义为 an ,因此将必然方法放在同一个对象上object会稍微复杂一些。abstract @Binds您可能需要采用其他解决方案之一以使该拓扑适用于您的案例,包括使用 acompanion object来捕获 else-static @Provides方法:


推荐阅读