迁移到 2.17 后 Dagger 失败

Dagger fails after migrating to 2.17

我有两个模块 :app:settings。这是我的匕首配置。

我的组件:

@ApplicationScope
@Component(
    modules = [
        AndroidInjectionModule::class,
        AndroidSupportInjectionModule::class,
        RoutingModule::class,
        SettingsModule::class
    ]
)
interface ELanguageComponent {

    @Component.Builder
    interface Builder {

        @BindsInstance
        fun application(application: Application): Builder
        fun build(): ELanguageComponent
    }

    fun inject(application: BaseELanguageApplication)
}

RoutingModule:

@Module
class RoutingModule {

    @Provides
    fun ProvidesettingsFragmentRouter(router: SettingsRouter): SettingsFragment.Router = router
}

SettingsRouter:

class SettingsRouter @Inject constructor(
    private val applicationStateManager: ApplicationStateManager
) : SettingsFragment.Router

SettingsModule:

@Module
abstract class SettingsModule {

    @ActivityScope
    @ContributesAndroidInjector(modules = [SettingsFragmentModule::class, ApplicationStateManagerModule::class])
    abstract fun settingsActivity(): SettingsActivity
}

@Module
abstract class ApplicationStateManagerModule {

    @Module
    companion object {

        @JvmStatic
        @Provides
        fun bindApplicationStateManager(settingsActivity: SettingsActivity): ApplicationStateManager = settingsActivity
    }
}

我的SettingsFragmentModule:

@Module
abstract class SettingsFragmentModule {

    @FragmentScope
    @ContributesAndroidInjector
    abstract fun settingsFragment(): SettingsFragment
}

并且 SettingsFragment.Router 被注入我的 SettingsFragment:

class SettingsFragment : DaggerFragment() {

  @Inject
  lateinit var router: Router
  
  ...
}

我已经找到并阅读了 this article 但它没有多大帮助,因为错误不是那么解释:

[Dagger/MissingBinding] com.altissia.common.authentication.ApplicationStateManager cannot be provided without an @Provides-annotated method. public abstract interface ELanguageComponent { ^ com.altissia.common.authentication.ApplicationStateManager is injected at com.altissia.router.SettingsRouter(applicationStateManager, …) com.altissia.router.SettingsRouter is injected at com.altissia.injection.module.RoutingModule.ProvidesettingsFragmentRouter(router) com.altissia.settings.fragment.SettingsFragment.Router is injected at com.altissia.settings.fragment.SettingsFragment.router com.altissia.settings.fragment.SettingsFragment is injected at dagger.android.AndroidInjector.inject(T) [com.altissia.injection.component.ELanguageComponent → com.altissia.settings.injection.module.SettingsModule_SettingsActivity.SettingsActivitySubcomponent → com.altissia.settings.injection.module.SettingsFragmentModule_SettingsFragment.SettingsFragmentSubcomponent]

我在这里错过了什么? ApplicationStateManager 通过安装在 SettingsModule.

中的 ApplicationStateManagerModule 提供

您应该使用贡献者模块将 SettingsFragment 添加到设置Activity

    @ActivityScope
    @ContributesAndroidInjector(modules = [
       ApplicationStateManagerModule::class, 
       FragmentContributorModule::class])
    abstract fun settingsActivity(): SettingsActivity

贡献者模块是这样的

@Module
abstract class FragmentContributorModule {

    @FragmentScope
    @ContributesAndroidInjector(modules = [SettingsFragmentModule::class])
    abstract fun contributeSettingsFragment(): SettingsFragment
}

我以前使用 dagger-android 的设置是

AppComponent

    @Component(modules = [
        AndroidSupportInjectionModule::class,
        AppModule::class,
        ActivityContributorModule::class])
    /*
     * ActivityContributorModule defines which Activities will have which modules and inject objects
     * If an Activity has any fragments it should add them via FragmentContributorModule with @ContributesAndroidInjector
     * @ContributesAndroidInjector(modules = {MainActivityModule.class, FragmentContributorModule.class})
     */
 @Singleton
interface AppComponent : AndroidInjector<MyApplication> {

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder

        fun build(): AppComponent
    }

    override fun inject(myApplication: MyApplication)

}

和Activity设置为ActivityContributorModule

@Module
abstract class ActivityContributorModule {
    
    @ActivityScope
    @ContributesAndroidInjector(modules = [MainActivityModule::class, FragmentContributorModule::class])
    abstract fun contributeMainActivity(): MainActivity

    @ActivityScope
    @ContributesAndroidInjector(modules = [SecondActivityModule::class])
    abstract fun contributeSecondActivity(): SecondActivity
    
    @ActivityScope
    @ContributesAndroidInjector
    abstract fun contributeThirdActivity(): ThirdActivity
}

以及Activities要使用的片段

@模块

abstract class FragmentContributorModule {
    /**
     * FragmentContributorModule is used inside ActivityContributorModule
     * With @ContributesAndroidInjector(modules = MyFragmentModule.class)
     * defines which module will be used to inject objects to MyFragment
     *
     *
     * In this example [MainActivity] has [FirstFragment] fragment1, and [FirstFragment]
     * uses [FirstFragmentModule] to inject objects
     *
     *
     *
     * Scope of @ContributesAndroidInjector methods and their modules should be same.
     * Otherwise app returns HAS CONFLICTING SCOPES error
     *
     */
    @FragmentScope
    @ContributesAndroidInjector(modules = [FirstFragmentModule::class])
    abstract fun contributeMyFragment(): FirstFragment
}

自从匕首柄问世以来,它就已经过时了。实现依赖注入要容易得多。

您可以查看此 github link 您可以参考 dagger-android 具有作用域的组件或 Hilt 实现。

链接文章中的情况适用于此。

  • SettingsFragment 请求 SettingsFragment.Router.
  • SettingsFragment.Router 依赖于 SettingsRouter,这个绑定在应用程序组件中。
  • SettingsRouter 通过 @Inject 构造函数依赖于 ApplicationStateManager
  • ApplicationStateManager 绑定在您的(生成的)activity 子组件中。

因此,您在父组件中有一个绑定,需要在子组件中进行绑定。如文章中所述,解决此问题的最简单方法是将 RoutingModule 移动到 activity(或片段)子组件中。