I have the following interface called SettingHandler
that is responsible for handling events related to a particular setting inside the Android app.
interface SettingHandler {
fun onHandleEvent(event: SettingEvent)
fun candleHandleEvent(event: SettingEvent): Boolean
fun getSettingId(): SettingId
}
Then let's say I have the following Dagger module:
@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 {
//
}
}
As you can see, nothing too special here, expect for the SettingHandlerB
and SettingHandlerC
provider methods. They both depend on each other, so I've decided to resolve this circular dependency using the Dagger supplied Provider class. Since I require a concrete implementation of a setting handler (SettingHandlerC
for the SettingHandlerB
and SettingHandlerB
for the SettingHandlerC
), I now need to differentiate between them. That's where a @Qualifier
annotation comes into play. I created the following qualifier annotation to differentiate among different implementations.
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER)
annotation class SettingHandlerType(val id: SettingId)
SettingId
is basically an enumeration that contains all possible setting constants. So now my SettingHandler
s module looks as follows:
@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 {
//
}
}
And here comes the problem. Mutlibinding now does not work, because all my SettingHandler
s are annotated with a @SettingHandlerType
annotation and a Set that I'm injecting into the SettingsPresenter
also needs to be annotated. However, annotating it with, for example, @SettingHandlerType(SettingId.A)
won't work because in that case the Set will contain only setting handlers with that particular qualifier (SettingHandlerA
, in this case). How can I construct a Set data structure using multibinding because I really don't want to provide another provider method where I'll be constructing it myself?
Any help would be much appreciated. Thanks in advance.
You want two different types of data: Individual handlers of type @SettingHandlerType(/*...*/) SettingHandler
and a set of type Set<SettingHandler>
. I think the best way would be to have each definition come with a @Binds @IntoSet
complement.
@Binds @IntoSet abstract fun bindSettingHandlerA(
@SettingHandlerType(SettingId.A) handler: SettingHandler): SettingHandler
Unfortunately, since you've defined this as an object
in Kotlin, it's slightly more complicated to put the necessarily-abstract
@Binds
methods on the same object. You may need to pursue one of these other solutions to make that topology work with your case, including the use of a companion object
to capture the otherwise-static
@Provides
methods: