这是我的情景:
BaseActivity
在BaseActivity
中,我想注入Navigator
(它帮助我管理Fragments
后台并在活动之间导航:
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
答案 0 :(得分:3)
问题在于你假设你需要在某个时候注入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
}
使用上面的代码,你最终会得到一些注入MainActivity
的组件,以及一些注入BaseActivity
的组件,但是两者都不能注入“both”。您收到的错误是因为MainActivity
无法提供其父FragmentManager
注入所需的BaseActivity
。它缺少这样做的模块。您只需将BaseActivityModule
添加到您的其他组件,MainActivityComponent实际上无法访问该组件,因此无法提供 错误。
Dagger总是需要注入整个对象。没有部分注射,或一次注射多个组件。如果单个组件无法提供所有所需的依赖项,则会出现错误。您的fun bindBaseActivity(): BaseActivity
没用,因为您永远不会使用BaseActivity
,但您只会使用MainActivity
或其他子类。 那些组件也需要能够提供BaseActivity的依赖关系。
如果要在BaseActivity中注入依赖项,则需要添加一个提供必要绑定的模块。您的代码最终应如下所示:
@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
MainActivity
绑定到另一个模块中作为您的BaseActivity
,以便您可以在模块中使用它,而不必为每个活动绑定FragmentManager 虽然您可以重复使用BaseActivityModule
并将其添加到所有活动实施中,但您必须添加一个模块,将活动绑定为BaseActivity
,用于您的每项活动。
可能有一种更优化的方法,但这是注入子类的香草要求。
答案 1 :(得分:0)
主要想法是要了解Dagger只了解顶级组件/活动注入,但看不到BaseActivityComponent
@David Medenjak解决方案的替代实施方法是简单地包含BaseActivityModule
并注入BaseActivity
:
@ActivityScope
@Subcomponent(modules = {MainActivityModule.class, BaseActivityModule.class} )
public interface PlayerActivityComponent {
void inject(MainActivity activity);
void inject(BaseActivity activity);
}
您现在可以在BaseActivity
和MainActivity