这是我的情况:

  • 我希望所有 Activity 都可以从BaseActivity继承
  • BaseActivity内,我想注入(inject)Navigator(这有助于我管理Fragments的堆栈并在 Activity 之间导航):
    abstract class BaseActivity : DaggerAppCompatActivity() {
        @Inject
        lateinit var navigator: Navigator
    
        @Inject
        lateinit var prefs: SharedPreferences // injected via AppModule.kt, see below.
    }
    
  • Navigator类在其构造函数中需要一个FragmentManager:
    class Navigator @Inject constructor(
        val fragmentManager: FragmentManager) {
        // class body
    }
    
  • 我想从FragmentManager中的BaseActivity对象提供BaseActivityModule:
    @Module
    class BaseActivityModule {
        @PerActivity
        @Provides
        fun provideFragmentManager(baseActivity: BaseActivity): FragmentManager {
            return baseActivity.supportFragmentManager
        }
    }
    

  • 这是我其余的组件和模块:
  • AppComponent.kt
    @Singleton @Component(modules = [
        AndroidSupportInjectionModule::class,
        AppModule::class,
        ActivityBindingModule::class])
    interface AppComponent {
        @Component.Builder
        interface Builder {
            @BindsInstance
            fun application(application: Application): Builder
            fun build(): AppComponent
        }
        fun inject(app: AndroidApplication)
    }
    
  • AppModule.kt
    @Module
    class AppModule {
        @Singleton
        @Provides
        fun providesPrefs(application: Application): SharedPreferences {
            return application.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE)
        }
    }
    
  • ActivityBindingModule.kt
    @Module
    abstract class ActivityBindingModule {
        @ContributesAndroidInjector
        abstract fun bindMainActivity(): MainActivity
    
        @ContributesAndroidInjector(modules = [(BaseActivityModule::class)])
        abstract fun bindBaseActivity(): BaseActivity
    }
    
  • BaseActivityModule.kt
    @Module
    class BaseActivityModule {
        @Provides
        fun provideFragmentManager(baseActivity: BaseActivity): FragmentManager {
            return baseActivity.supportFragmentManager
        }
    }
    

  • 这是编译错误消息:
    Error: [dagger.android.AndroidInjector.inject(T)]
    android.support.v4.app.FragmentManager cannot be provided
    without an @Provides- or @Produces-annotated method.
    
    Error:A binding with matching key exists in component:
    com.myapp.ActivityBindingModule_BindBaseActivity.BaseActivitySubcomponent
    

    最佳答案

    问题在于您假设您需要在某个时候注入(inject)BaseActivity ...

    @Module
    abstract class ActivityBindingModule {
      @ContributesAndroidInjector
      abstract fun bindMainActivity(): MainActivity
    
    
      // ...that's not really how it works... :/
      @ContributesAndroidInjector(modules = [(BaseActivityModule::class)])
      abstract fun bindBaseActivity(): BaseActivity
    }
    

    使用上面的代码,您最终得到一些组件来注入(inject)MainActivity,而某些组件来注入(inject)BaseActivity,但是两者都不能注入(inject)“both”。您收到的错误是因为MainActivity无法提供需要注入(inject)其父FragmentManager中的BaseActivity。它缺少这样做的模块。您只能将BaseActivityModule添加到MainActivityComponent实际上无法访问的其他组件中,因此无法提供错误。

    Dagger 始终需要注入(inject)整个对象。没有局部注入(inject),也没有一次从多个组件注入(inject)。如果单个组件不能提供它需要的所有依赖关系,则会出现错误。您的fun bindBaseActivity(): BaseActivity没用,因为您将永远不会使用BaseActivity,而只会使用MainActivity或它的其他子类。这些组件还必须能够提供BaseActivity的依赖项。

    如果要在BaseActivity中注入(inject)依赖项,则需要添加一个提供必要绑定(bind)的模块。您的代码最终应如下所示:
    @Module
    abstract class ActivityBindingModule {
      @ContributesAndroidInjector(modules = [BaseActivityModule::class, MainActivityModule::class])
      abstract fun bindMainActivity(): MainActivity
    
      // no BaseActivity component necessary
    }
    
    @Module
    abstract class MainActivityModule {
      @Binds
      abstract fun bindBaseActivity(activity: MainActivity) : BaseActivity
    }
    

    这将执行以下操作:
  • 它将BaseActivityModule添加到MainActivityComponent,以便此组件可以提供您的基本依赖关系,并且可以将MainActivity注入(inject)
  • 它将MainActivity绑定(bind)到另一个模块中作为BaseActivity,以便您可以在模块中使用它,而不必为拥有
  • 的每个 Activity 都绑定(bind)FragmentManager

    尽管您可以重用BaseActivityModule并将其添加到所有 Activity 实现中,但是您将必须添加一个模块以将 Activity 作为BaseActivity绑定(bind)到每个 Activity 中。

    可能有一种更优化的方法,但这就是注入(inject)子类的基本要求。

    10-08 20:04