【问题标题】:Dagger fails after migrating to 2.17迁移到 2.17 后 Dagger 失败
【发布时间】:2020-07-27 08:53:12
【问题描述】:

我有两个模块 :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,但这并没有多大帮助,因为错误不是那么解释性:

[匕首/缺失绑定] com.altissia.common.authentication.ApplicationStateManager 不能 在没有 @Provides 注释的方法的情况下提供。公共摘要 接口语言组件 { ^ com.altissia.common.authentication.ApplicationStateManager 在注入 com.altissia.router.SettingsRouter(applicationStateManager, ...) com.altissia.router.SettingsRouter 被注入 com.altissia.injection.module.RoutingModule.ProvidesettingsFragmentRouter(路由器) com.altissia.settings.fragment.SettingsFragment.Router 在注入 com.altissia.settings.fragment.SettingsFragment.router com.altissia.settings.fragment.SettingsFragment 被注入 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 提供的。

【问题讨论】:

    标签: android dependency-injection dagger-2


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

      您应该使用贡献者模块将 SettingsFragment 添加到 SettingsActivity

          @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 一起使用的设置是

      应用组件

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

      和使用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
      }
      

      以及活动要使用的片段

      @模块

      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,您可以参考具有作用域组件或 Hilt 实现的 dagger-android。

      【讨论】:

        猜你喜欢
        • 2020-04-09
        • 2015-07-30
        • 2015-06-19
        • 2011-01-31
        • 1970-01-01
        • 2019-12-25
        • 2020-09-07
        • 2022-11-01
        • 1970-01-01
        相关资源
        最近更新 更多