【问题标题】:Dagger Hilt with multiple implementations of an interface具有多个接口实现的 Dagger Hilt
【发布时间】:2021-11-11 22:32:29
【问题描述】:

使用 Dagger2 可以很容易地显式创建组件并列出它们的依赖项。但是我似乎无法找到一种方法来提供接口的不同实现来让我们说一个片段。

例如,我的应用有 2 种生产模式:付费和免费。 我有一个 PaidActivity 和一个 FreeActivity,它们都使用 Analytics 类开始完全相同的仪表板片段。对于付费,我提供了一个 PaidAnalytics 实现,对于免费,我提供了一个 FreeAnalytics 实现。

使用 Dagger2,只需在 Activity 的组件(或子组件)中列出付费或免费模块即可轻松实现。

@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

    ...

}

我找不到匕首柄的方法。

【问题讨论】:

  • 不,它需要不同的限定符,您必须在编译时指定。我需要在运行时切换依赖项。
  • 其实我已经知道答案了,只是没有在这里给出正确的答案。匕首刀柄不可能在运行时为我的特定用例提供不同的接口实现。

标签: android dependency-injection dagger-2 dagger-hilt


【解决方案1】:

在我的用例中,使用 Dagger 在运行时替换依赖项是不可能的。

在一次 Google Hilt 会话期间,他们建议在 Provides 方法中使用 if else 语句:https://youtu.be/i27aNF-kYR4?t=3355(这是我希望避免的)。

上面的答案不理解我的问题,因为它们在编译时是限定依赖项,而我做不到。因为我的片段永远不知道它被使用的地方,我不想只是重复代码。

这是一个示例,您可以准确地看到我在做什么,而 Hilt 无法通过设计实现它:https://github.com/dmytroKarataiev/daggerAndroidvsHiltRuntimeDependencies

【讨论】:

  • 您可以尝试对不同的依赖项使用 @Named("value") 限定符。就像在您的片段中一样,您可以执行 @Named(VersionType) @Inject val 分析之类的操作。这个 VersionType 将是一个全局变量,您可以在任何地方更改其值。这里唯一需要注意的是在实际创建片段之前更改 VersionType 的值
  • @Named 注解中不能有变量,所有东西都必须在编译时可用。 Dagger 无法使用动态变量生成代码。而且即使可能,这种方法也与在某处使用常规 if/else 语句相同,这是我需要避免的。
【解决方案2】:

我认为我们可以利用 Hilt 的 Qualifier 功能来解决这个多重绑定问题。 这是我找到的一些资源:https://developer.android.com/codelabs/android-hilt#8 我引用:

要告诉 Hilt 如何提供相同类型的不同实现(多个绑定),您可以使用限定符。

我认为这是 Hilt 区分同一接口的不同实现的一种方式。

设置您的 Hilt 模块:

@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
}

注入:

@FreeModule
@Inject
lateinit var freeActivity: YourInterface

@PaidModule
@Inject
lateinit var paidActivity: YourInterface

【讨论】:

  • 不是这样,这与 cmets 中链接到我的问题的答案相同。我需要能够在不使用限定符的情况下注入接口。考虑一个用于 2 个不同活动的 Fragment,但它必须注入 YourInterface 的不同实现。
  • 哦,抱歉,我无法提供您正在寻找的答案。但是对于给定的信息,这是有限的。我只能想到这个答案。除非您可以在问题中添加更多信息。首先,也许界面是什么样的?哪些片段? Fragment 应该注入到哪里?
  • 我相信这个问题有你需要的一切。我将创建一个带有示例的 repo,以向您展示我的意思。
  • 我将在此 repo 中添加更多详细信息和图表:github.com/dmytroKarataiev/… 但我相信不可能使用 Dagger Hilt 为不同的 Analytics 实例注入 BlankFragment。
猜你喜欢
  • 2023-03-26
  • 2020-05-22
  • 1970-01-01
  • 2019-10-12
  • 1970-01-01
  • 2013-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多