如何使用dagger.android注入抽象的BaseActivity及其子类?

6
我正在使用Dagger 2中的新dagger.android包,在我的项目中注入Android依赖项。
  • I need all my Activities to be a subclass of an abstract BaseActivity
  • In my BaseActivity I have member variables to be injected. This way:

    abstract class BaseActivity : AppCompatActivity() {
        @Inject
        lateinit var prefs: MyPreferenceDataStore
        ...// more @Injected members
    }
    
  • I do it because I want subclasses of BaseActiviy can have access to injected members of BaseActivity:

    class SubClassActivity : BaseActivity() {
        override fun onCreate(savedInstanceState: Bundle) {                
            val x = prefs.getXXX //use prefs variable from parent class
        }
    }
    
  • This is my ApplicationComponent:

    @Singleton @Component(modules = arrayOf(
                    ApplicationModule::class,
                    ActivityBindingModule::class,
                    AndroidSupportInjectionModule::class
                ))
    interface ApplicationComponent {
        @Component.Builder interface Builder {
            @BindsInstance
            fun application(application: Application): Builder
            fun build(): ApplicationComponent
        }
        fun inject(app: AndroidApplication)
    }
    
  • The ApplicationModule class has simple @Provides annotated methods:

    @Module
    class ApplicationModule {
        @Singleton @Provides
        fun providesMyPreferenceDataStore(context: Context): MyPreferenceDataStore {
            return MyPreferenceDataStoreImpl(context)
        }
        // more @Provides annotated methods
    }
    

    I think the problem is in my ActivityBindingModule

    @Module
    abstract class ActivityBindingModule {
    
        @PerActivity
        @ContributesAndroidInjector(
            modules = arrayOf(BaseActivityModule::class
        ))
        abstract fun bindBaseActivity(): BaseActivity
    
        @PerActivity
        @ContributesAndroidInjector(
            modules = arrayOf(
                BaseActivityModule::class
        ))
        abstract fun bindSubClassActivity(): SubClassActivity
    }
    

这是我到目前为止尝试过的:

  • Make the bindSubClassActivity() method not to depend of BaseActivityModule::class, didn't work.

  • Move the providesMyPreferenceDataStore from ApplicationModule to the BaseActivityModule, so that the class is:

    @Module
    class BaseActivityModule {
        @PerActivity @Provides
        fun providesMyPreferenceDataStore(context: Context): MyPreferenceDataStore {
            return MyPreferenceDataStoreImpl(context)
        }
    }
    

这是我收到的错误:

Error: [dagger.android.AndroidInjector.inject(T)] com.example.BaseActivity cannot
be provided without an @Provides-annotated method.
This type supports members injection but cannot
be implicitly provided.

BaseActivityModule 代码在哪里? - Ahmed Abdelmeged
嗨@AhmedAbd-Elmeged,请查看编辑。 - Jorge E. Hernández
1个回答

8
我不完全理解你想做什么,但这个解决方案是基于我所理解的内容。
AppComponent 应该像这样:
@Singleton
@Component(modules = [
    AndroidSupportInjectionModule::class,
    AppModule::class,
    ActivityModule::class])
interface AppComponent : AndroidInjector<DaggerApplication> {

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

        fun build(): AppComponent
    }
}

您的基础活动,它将注入所有对象。

abstract class BaseActivity : DaggerAppCompatActivity() {

    @Inject
    lateinit var prefs: SharedPreferences

    //other objects to inject

}

它将被继承的活动,例如:MainActivity。
class MainActivity : BaseActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        prefs.getBoolean("s", true)
    }

}

活动模块

@Module
abstract class ActivityModule {

    @ContributesAndroidInjector
    abstract fun bindMainActivity(): MainActivity

    @ContributesAndroidInjector
    abstract fun bindBaseActivity():BaseActivity

}

应用程序模块

@Module
class AppModule {

    @Singleton
    @Provides
    fun providesMyPreferenceDataStore(application: Application): SharedPreferences {
        return application.getSharedPreferences("test", Context.MODE_PRIVATE)
    }

}

它起作用了。现在我有另一个问题,但它是另一个问题的一部分。谢谢! - Jorge E. Hernández
没问题,问吧 :D - Ahmed Abdelmeged
我需要编辑整个问题。我会发布另一个问题并在这里通知您。 - Jorge E. Hernández
3
我认为最好提出一个新问题,这样如果有人遇到相同的问题,就可以找到解决方案。 - Ahmed Abdelmeged
在一个大型/生产应用程序中,您不会将它们放在一个类中,而是会进行模块化和范围限定。例如,您有一个注册模块,其中包含所有的登录注册UI,一个用于支付等,具体取决于您的用例。此外,如果您有例如5个用户片段在一个活动中使用,您将把它们放在一个模块中,并将它们限定在活动范围内@MaulikDodia - Ahmed Abdelmeged
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接