给定BaseFragment及其子类:DerivedFragmentA,DerivedFragmentB,......
让我们说,大多数@Inject
字段对于每个片段都是通用的,因此在BaseFragment中声明:
abstract class BaseFragment : DaggerFragment() {
@Inject lateinit var vmFactory: ViewModelProvider.Factory
}
class DerivedFragmentA : BaseFragment()
class DerivedFragmentB : BaseFragment()
...
对于每个派生片段,我们必须手动创建模块 - 组件对,例如:
@Subcomponent
interface DerivedFragmentAComponent : AndroidInjector<DerivedFragmentA> {
@Subcomponent.Builder
abstract class Builder : AndroidInjector.Builder<DerivedFragmentA>()
}
@Module(subcomponents = [DerivedFragmentAComponent::class])
abstract class DerivedFragmentAModule {
@Binds @IntoMap @FragmentKey(DerivedFragmentA::class)
abstract fun bind(builder: DerivedFragmentAComponent.Builder): AndroidInjector.Factory<out Fragment>
}
并将它们安装到某个外部组件中,如下所示:
@Subcomponent(modules = [DerivedFragmentAModule::class, DerivedFragmentBModule::class, ...])
interface MainComponent : AndroidInjector<MainActivity> {
@Subcomponent.Builder
abstract class Builder : AndroidInjector.Builder<MainActivity>()
}
但这是一种样板。
如果我们尝试只为BaseFragment创建一个Module-Component并仅将其安装到MainComponent - 我们将在调用AndroidInjector.inject(fragment)
方法期间获得运行时异常,并显示以下消息:
"No injector factory bound for Class<DerivedFragmentA>. Injector factories were bound for supertypes of DerivedFragmentA: BaseFragment. Did you mean to bind an injector factory for the subtype?"
有没有办法解决这个问题并避免代码重复?或者Dagger-2强烈依赖于类名,impossible?
答案 0 :(得分:0)
使用Dagger 2进行注入始终适用于您指定的类型。 inject(fragment : BaseFragment)
只会注入BaseFragment
的字段,而不会注入任何子类中声明的字段。这只是你必须记住的事情。
您说您只想声明一个组件并仅将内容注入BaseFragment
,这样您就可以 做什么。不是为DerivedFragment
创建子组件,而是为BaseFragment
...
@Subcomponent
interface BaseFragmentComponent : AndroidInjector<BaseFragment> {
@Subcomponent.Builder
abstract class Builder : AndroidInjector.Builder<BaseFragment>()
}
然后,您可以将BaseFragment.Builder
绑定到DerivedFragmentX
。
@Module(subcomponents = [BaseFragmentComponent::class])
abstract class BaseFragmentModule {
@Binds @IntoMap @FragmentKey(DerivedFragmentA::class)
abstract fun bind(builder: BaseFragmentComponent.Builder): AndroidInjector.Factory<out Fragment>
@Binds @IntoMap @FragmentKey(DerivedFragmentB::class)
abstract fun bind(builder: BaseFragmentComponent.Builder): AndroidInjector.Factory<out Fragment>
@Binds @IntoMap @FragmentKey(DerivedFragmentC::class)
abstract fun bind(builder: BaseFragmentComponent.Builder): AndroidInjector.Factory<out Fragment>
}
重要的是设置@FragmentKey(DerivedFragmentA::class)
来引用子类,因为在调用AndroidInjection.inject(fragment)
时,Dagger会查找一个。
我仍然建议你不要使用这种方法,因为你最终会混合使用完全注入的一些片段,而其他片段只是BaseFragment。这听起来让我感到困惑。
您可以使用@ContributesAndroidInjector
代替为您生成样板代码并正确注入每个片段。