android - 如何使用 dagger.android 在 BaseActivity 中 @Inject 成员?

标签 android dependency-injection kotlin dagger-2

这是我的场景:

  • 我希望我所有的 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
    }
    
  • 我想从 BaseActivityModule 中的 BaseActivity 对象提供 FragmentManager:

    @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)。您收到的错误是因为 MainActivity 无法提供它需要在其父级 BaseActivity 中注入(inject)的 FragmentManager。它缺少这样做的模块。您仅将 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
}

这会做以下事情:

  1. 它将 BaseActivityModule 添加到 MainActivityComponent,这样您的基础依赖项就可以由该组件提供,并且可以注入(inject) MainActivity
  2. 它将另一个模块中的 MainActivity 绑定(bind)为您的 BaseActivity,这样您就可以在您的模块中使用它,而不必为您拥有的每个 Activity 都绑定(bind)一个 FragmentManager

虽然您可以重用 BaseActivityModule 并将其添加到所有 Activity 实现中,但您必须添加一个模块以将 Activity 绑定(bind)为 BaseActivity你的 Activity 。

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

关于android - 如何使用 dagger.android 在 BaseActivity 中 @Inject 成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48533899/

相关文章:

android - (Android)是否可以更改谷歌地图中多段线的形状?

javascript - Angular 模块注入(inject)错误

scala - 如何在 scala 中进行依赖注入(inject)?

android - 无法解析以下类的父类(super class)型

java - Android AdMob - NoSuchMethodError : No static method zzand()

android - "ERROR: OpenGLES initialization failed!"在 CentOS 与 android SDK

java - 如何在 Android 中通过指纹搜索

java - 在 Guice 中管理同一依赖树的多个版本的最佳模式是什么?

generics - Star 投影集合中的特定 KClass

ios - 如何在 Kotlin Multiplatform Mobile 中使用 Swift 中 Flow 中的密封类数据?