非全局活动范围内的依赖注入正确完成。如何提供特殊的MyActivity作为活动

时间:2018-01-18 21:11:41

标签: android dependency-injection kotlin dagger-2 dagger

我正在使用依赖注入为活动提供全局对象(@Singleton)和非全局对象(@ActivityScoped)。

现在我想知道我是否做得对,如果可以做得更好。 DI实现中最有趣的部分是将对象SomeManager注入到具有受限范围的2个不同活动中

这是代码

主要应用组件

@Singleton
@Component(modules = [
    ApplicationModule::class,
    AndroidSupportInjectionModule::class,
    ActivityModule::class,
    ManagerModule::class,
    ...
    ClientModule::class])
interface AppComponent : AndroidInjector<App> {

    @Component.Builder
    interface Builder {

        @BindsInstance
        fun application(application: Application): AppComponent.Builder

        fun build(): AppComponent
    }
}

应用程序模块

@Module
abstract class ApplicationModule {

    @Binds
    @Singleton
    internal abstract fun bindContext(application: Application): Context

}

活动模块

@Module
abstract class ActivityModule {

    @ActivityScoped
    @ContributesAndroidInjector(modules = [MainActivityModule::class])
    internal abstract fun mainActivity(): MainActivity

    @ActivityScoped
    @ContributesAndroidInjector(modules = [LoginActivityModule::class])
    internal abstract fun loginActivity(): LoginActivity
}

现在我想向SomeManager注入一个新的LoginActivity,为MainActivity注入一个新的@ContributesAndroidInjector(modules...

该方法为每个活动设置了一个模块,就像您在@Module object MainActivityModule { @JvmStatic @Provides @ActivityScoped internal fun provideSomeManager(activity: MainActivity, apiClient: ApiClient) = SomeManager(activity, apiClient) } 注释中看到的那样。这两个文件的实现看起来像这样

@Module
object LoginActivityModule {

    @JvmStatic
    @Provides
    @ActivityScoped
    internal fun provideSomeManager(activity: LoginActivity, apiClient: ApiClient) =
            SomeManager(activity, apiClient)
}

LoginActivityModule

问题:

1)现在MainActivityModuleSomeManager看起来非常相似。是否有更好的方法为这两项活动提供@Singleton而不制作SomeManager而没有为每项活动创建模块(因为Activity只需要Activity,而不是特殊sublcass)?我有一些想法,只需要XXXActivity而不是特定的XXXActivity但我如何告诉匕首提供Activity MainActivity

2)除了1)中的优化之外,这是一个正确的实现吗?

更新1

我通过以下实现解决了这个问题。 这是正确的方法吗?

Activity提供为@Module object MainActivityModule { @JvmStatic @Provides @ActivityScoped internal fun provideAsActivity(activity: MainActivity): Activity = activity }

的模块
MainActivity

Activity提供为@Module object LoginActivityModule { @JvmStatic @Provides @ActivityScoped internal fun provideAsActivity(activity: LoginActivity): Activity = activity }

的模块
@ActivityScoped

@Module object ManagerModule2 { @JvmStatic @Provides @ActivityScoped internal fun provideSomeManager(activity: Activity, apiClient: ApiClient) = SomeManager(activity, apiClient) }

的经理模块
@Module
abstract class ActivityModule {

    @ActivityScoped
    @ContributesAndroidInjector(modules = [ManagerModule2::class, MainActivityModule::class])
    internal abstract fun mainActivity(): MainActivity

    @ActivityScoped
    @ContributesAndroidInjector(modules = [ManagerModule2::class, LoginActivityModule::class])
    internal abstract fun loginActivity(): LoginActivity
}

用于活动的Android注入器

1) Error in data.frame(..., check.names = FALSE) : 
  arguments imply differing number of rows: 1, 2, 0
and
2) Warning message:
In mean.default(sapply(e, function(x) { :
  argument is not numeric or logical: returning NA

1 个答案:

答案 0 :(得分:3)

  

现在LoginActivityModuleMainActivityModule看起来非常相似。有没有更好的方法为这两项活动提供SomeManager而不制作@Singleton?我有一些想法,只需要Activity而不是特定的XXXActivity

是的,你可以这样做。您可以替换特定活动的依赖关系,并将其替换为ActivityContext(取决于您的实际需要),并将该声明移动到一个单独的模块中,您可以将其包含在两个ActivityModule中。

@Module
object SomeManagerModule {

    @JvmStatic
    @Provides
    @ActivityScoped
    internal fun provideSomeManager(activity: Activity, apiClient: ApiClient) =
            SomeManager(activity, apiClient)
}

要么将其包含在模块中,要么将其添加到ContributesAndroidInjector

@Module(includes = [SomeManagerModule::class])
object MainActivityModule { /* ... */ }

// or

@ActivityScoped
@ContributesAndroidInjector(modules = [LoginActivityModule::class, SomeManagerModule::class])
internal abstract fun loginActivity(): LoginActivity

您甚至可以通过使用构造函数注入来完全删除对模块的需求。

@ActivityScoped
SomeManager @Inject constructor(activity: Activity, apiClient: ApiClient)

无论哪种方式,您都必须将xxxActivity绑定/提供为某个Activity,以便Dagger可以找到它们。

  

除了1)中的优化之外,这是一个正确的实现吗?

对我来说很好看。你说每个Activity都需要一个新的经理,所以@ActivityScoped似乎是正确的选择。如果您不必确保每个活动范围的组件只有一个,那么您可以完全删除范围,但这取决于您的确切用例。