【问题标题】:Dagger 2 can't inject from subcomponentDagger 2 无法从子组件注入
【发布时间】:2017-12-13 05:17:50
【问题描述】:

我知道通常使用 Kotlin 应该不会有什么不同,但我遇到了一些奇怪的情况,即 @Named 限定符需要 Kotlin 中的范围。

我有一个 ViewHolderFactory 类,它允许我创建视图类型的简单映射 -> 视图持有者类:

@Singleton
class ViewHolderFactoryImpl @Inject constructor(
        private val viewHolderComponentProvider: Provider<ViewHolderSubcomponent.Builder>
): ViewHolderFactory(mapOf(
        R.layout.view_error to ErrorViewHolder::class.java,
        R.layout.view_soft_error to SoftErrorViewHolder::class.java,
        R.layout.view_empty to EmptyViewHolder::class.java,
        R.layout.view_loading to LoadingViewHolder::class.java,
        R.layout.item_got_it to GotItViewHolder::class.java)) {

    override fun createViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val viewHolder = super.createViewHolder(parent, viewType)
        if (viewHolder is Injectable) {
            viewHolderComponentProvider.get()
                    .viewHolder(viewHolder)
                    .build()
                    .inject(viewHolder)
        }
        return viewHolder
    }
}

ViewHolderSubcomponent 定义如下,目标是能够为每个视图持有者创建一个子组件并注入一些东西:

@ViewHolderScope
@Subcomponent(modules = [ViewHolderModule::class])
interface ViewHolderSubcomponent {

    fun inject(viewHolder: RecyclerView.ViewHolder)

    fun viewHolder(): RecyclerView.ViewHolder

    @Subcomponent.Builder
    interface Builder {
        @BindsInstance
        fun viewHolder(viewHolder: RecyclerView.ViewHolder): Builder
        fun build(): ViewHolderSubcomponent
    }
}

ViewHolderModule 定义为:

@Module
class ViewHolderModule {
    @Provides @ViewHolderScope
    fun provideSectionTitleViewHolder(viewHolder: RecyclerView.ViewHolder): SectionTitleViewHolder =
            SectionTitleViewHolder(viewHolder.itemView)
}

当我运行应用程序时,我发现注入不起作用,我的@Inject lateinit var 值为空。查看生成的代码,我明白了原因:

@Override
public void inject(RecyclerView.ViewHolder viewHolder) {
  MembersInjectors.<RecyclerView.ViewHolder>noOp().injectMembers(viewHolder);
}

没有为此子组件创建MembersInjectors&lt;RecyclerView.ViewHolder&gt;。我不知道如何让它工作。我知道我应该能够注入不是由 dagger 创建的对象,我只是无法弄清楚我在这里缺少什么。

哦,如果有帮助的话,我确实确保将ViewHolderSubcomponent 包含在我的AppModulesubcomponents 列表中

【问题讨论】:

  • 我不是 100% 确定,但如果您的字段看起来像 @Inject lateinit var,它们可能不会在类文件中以 @Inject 注释字段结束。我仍在尝试将我的大脑包裹在how Kotlin handles annotations 周围,但请尝试@field:Inject 以防万一,并且绝对将其用于@Namedthis SO answer 的其他限定符注释。另外,请发布 ViewHolder 代码:目前,Dagger 似乎找不到任何 @Inject 字段,直到我们看到它,我才能做得更好。

标签: android kotlin dagger-2


【解决方案1】:

inject(viewHolder: RecyclerView.ViewHolder) 将始终是空操作,因为框架类(或本例中的大多数库)没有任何 @Inject 注释字段。 Dagger 只会为您的 inject(MyClass instance) 方法中命名的类生成代码,不会为其任何子类型生成代码

所以如果你有一个ErrorViewHolder : RecyclerView.ViewHolder,那么你必须使用一个有inject(ErrorViewHolder instance)方法的组件来生成注入ErrorViewHolder的代码。
澄清一下,因为它是生成的代码——而不是运行时的动态反射——调用inject(viewHolder: RecyclerView.ViewHolder) 就像你对viewHolder : ErrorViewHolder 所做的那样,仍然会尝试为RecyclerView.ViewHolder 注入字段,而不是ErrorViewHolder。如前所述,RecyclerView.ViewHolder 将始终是无操作的。

您将不得不修改您的设置,以便您可以提供可以注入特定视图的特定子组件,您不能将一个“通用”组件用于不同类型。您可以在RecyclerView.ViewHolderErrorViewHolder 之间创建一个基类,但话又说回来,您只能在基类中注入声明(和@Inject 注释)的字段,而不是特定的子类。

【讨论】:

  • 谢谢,这解决了。我将我的mapOf 移动到一个新的匕首模块中,该模块使用@Binds @IntoMap @IntKey(R.layout.view_holder_layout_id) 创建地图现在一切正常!
【解决方案2】:

Kotlin 属性本身并不为 Dagger 所知。您试图实现的目标可以作为字段或 setter 注入来处理。由于使用任何属性生成 setter,我通常选择@set:Inject

@set:Inject lateinit var myVar: Type

或者,您可以考虑构造函数注入。像这样,您可以将属性定义为val 和私有。

【讨论】:

    猜你喜欢
    • 2016-11-21
    • 2016-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-30
    • 2017-08-13
    • 1970-01-01
    相关资源
    最近更新 更多