Dagger 2无法从子组件中注入(Dagger 2 can't inject from subcomponent)

编程入门 行业动态 更新时间:2024-10-26 08:30:35
Dagger 2无法从子组件中注入(Dagger 2 can't inject from subcomponent)

我知道通常情况下,使用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值为null。 查看生成的代码,我可以看到原因:

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

没有为此子组件创建的MembersInjectors<RecyclerView.ViewHolder> 。 我无法弄清楚如何使这个工作。 我知道我应该能够注入不是由匕首创造的物体,我只是无法弄清楚我在这里缺少什么。

哦,如果它有帮助,我确实在我的AppModule的subcomponents列表中包含ViewHolderSubcomponent

I know that generally it shouldn't make a difference that this is using Kotlin, but I've run into odd cases where the @Named qualifier needed a scope in Kotlin.

I have a ViewHolderFactory class that allows me to create a simple mapping of view type -> view holder class:

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

The ViewHolderSubcomponent is defined below, the goal is to be able to create one subcomponent for each view holder and inject a few things:

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

The ViewHolderModule is defined as:

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

When I run the app I find that the injection didn't work, my @Inject lateinit var values are null. Looking at the generated code I can see why:

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

There's no MembersInjectors<RecyclerView.ViewHolder> created for this subcomponent. I can't figure out how to get this to work. I know that I should be able to inject into objects not created by dagger, I just can't quite figure out what I'm missing here.

Oh, if it helps any, I did make sure to include the ViewHolderSubcomponent in my AppModule's list of subcomponents

最满意答案

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.ViewHolder和ErrorViewHolder之间创建一个基类,但是再次,您只能在基类中注入声明的字段(和@Inject annotated),而不是特定的子类。

inject(viewHolder: RecyclerView.ViewHolder) will always be a no-op, because framework classes (or most libraries in this case) don't have any @Inject annotated fields. Dagger will only generate code for the class named in your inject(MyClass instance) methods, not for any of its sub-types.

So if you have a ErrorViewHolder : RecyclerView.ViewHolder, then you have to use a component that has a inject(ErrorViewHolder instance) method to generate code to inject ErrorViewHolder. To clarify, because it's generated code—and not dynamic reflection at runtime—calling inject(viewHolder: RecyclerView.ViewHolder) like you do with an viewHolder : ErrorViewHolder will still try to inject fields for RecyclerView.ViewHolder, not ErrorViewHolder. And RecyclerView.ViewHolder will always be a no-op as mentioned.

You will have to modify your setup quite a bit so that you can provide a specific subcomponent that can inject a specific viewholder, you can't use one "generic" component for different types. You could create a base class between RecyclerView.ViewHolder and ErrorViewHolder, but then again, you could only inject fields declared (and @Inject annotated) in your base class, not the specific child.

更多推荐

本文发布于:2023-08-07 13:55:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1464702.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:组件   从子   Dagger   inject   subcomponent

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!