简体   繁体   中英

Dagger Hilt with multiple implementations of an interface

With Dagger2 it's easy to explicitly create components and list their dependencies. But I can't seem to find a way to provide different implementations of an interface to lets say a fragment.

For example, my app has 2 production modes: paid and free. I have a PaidActivity and a FreeActivity, both of which start exactly the same Dashboard fragment with an Analytics class. For Paid I provide a PaidAnalytics implementation, for Free I provide a FreeAnalytics implementation.

With Dagger2 it's easily achieved by just listing a Paid or a Free Module in the Activity's Component (or Subcomponent).

@Module
abstract class FreeActivityModule {

    @ContributesAndroidInjector(
        modules = [
            FreeAnalyticsModule::class,
            DashboardFragmentModule::class
        ]
    )
    abstract fun injectFreeActivity(): FreeActivity

}

@Module
abstract class PaidActivityModule {

    @ContributesAndroidInjector(
        modules = [
            PaidAnalyticsModule::class,
            DashboardFragmentModule::class
        ]
    )
    abstract fun injectPaidActivity(): PaidActivity

}

@Module
abstract class DashboardFragmentModule {

    @ContributesAndroidInjector
    abstract fun injectDashboardFragment(): DashboardFragment

}

class DashboardFragment : Fragment() {

    ...

    @Inject
    lateinit var analytics: Analytics

    ...

}

With Dagger Hilt I couldn't find a way to do this.

With Dagger it is impossible to replace dependencies at runtime in my use case.

During one of the Google Hilt sessions they recommended to use an if else statement in a Provides method: https://youtu.be/i27aNF-kYR4?t=3355 (that's what I prefer to avoid).

The answer above doesn't understand my question, because they are qualifying dependencies at compile time which I can't do. Since my fragment never knows the place it's used and I don't want to just duplicate code.

Here's an example where you can see exactly what I'm doing and that it can't be achieved with Hilt by design: https://github.com/dmytroKarataiev/daggerAndroidvsHiltRuntimeDependencies

I think we could leverage Hilt's Qualifier feature to solve this multi binding issue. Here is some resources I found: https://developer.android.com/codelabs/android-hilt#8 I quote:

To tell Hilt how to provide different implementations (multiple bindings) of the same type, you can use qualifiers.

I think it's a way for Hilt to differentiate different implementations of the same interface.

To setup your Hilt module:

@Qualifier
annotation class PaidModule

@Qualifier
annotation class FreeModule

@InstallIn(ActivityComponent::class)
@Module
abstract class PaidActivityModule {

    @ActivityScoped
    @Binds
    @PaidModule
    abstract fun bindPaidModule(impl: PaidActivity): YourInterface
}

@InstallIn(ActivityComponent::class)
@Module
abstract class FreeActivityModule {

    @ActivityScoped
    @Binds
    @FreeModule
    abstract fun bindFreeModule(impl: FreeActivity): YourInterface
}

To inject:

@FreeModule
@Inject
lateinit var freeActivity: YourInterface

@PaidModule
@Inject
lateinit var paidActivity: YourInterface

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM