匕首2和依赖注入地狱?

时间:2018-06-24 23:00:53

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

您如何使用Kotlin的匕首?

我一直处于修复一个编译错误并转移到另一个错误的循环中,最后我回到步骤1

这就是我所需要的:

  • AppDependencies
  • GenericActivityDependencies
  • PerActivityDependency

这是我的主要依赖项:

应用

@Module
class ApplicationModule(private val application: Application) {
    @Provides
    @Singleton
    fun provideContext(): Application = this.application
}

@Singleton
@Component(modules = [ HttpModule::class, ApplicationModule::class ])
interface AppComponent {
    val app: Application
}

为什么我需要在模块中提供一次依赖关系,而在组件中再次定义它?

活动模块

@Module
class ActivityModule(private val activity: Activity) {

    @PerActivity
    @Provides
    @ActivityContext
    fun provideContext(): Context = activity
}

@Component(modules = [ActivityModule::class], dependencies = [AppComponent::class])
@ActivityContext
interface ActivityComponent {
    fun inject(activity: MainActivity)
}

HomeModule

@Module
class LandingModule {
    @PerActivity
    @Provides
    fun provideSomethig(): Something {
        return  Something()
    }
}
@SomeActivity
@Subcomponent(modules = [LandingModule::class])
interface LandingSubcomponent {
    val something: Something
}

到目前为止,我编写的代码超出了我的整个活动范围。

  • 我遇到无法从合并范围组件继承的错误
  • 无法生成Dagger源代码
  • 子组件需要不同的范围

我该如何实现?

kotlin有更好的di吗?

每个活动模块中都有一个我可以遵循的示例吗?

2 个答案:

答案 0 :(得分:3)

我了解您的无奈。我以前去过那里,花了我很多时间才能理解匕首。只是一个快速的演示/教程。

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
    fun context(): Context
}

@Module
class AppModule(private val application: Application) {
    @Provides
    @Singleton
    fun provideApplication(): Application= application
}

该组件是容器的接口。如果您能够成功实例化容器,则可以访问此处定义的任何内容。另外,它是其他容器/组件的接口。这意味着,如果要在容器外部公开某些内容,请在此处进行定义。因此,

  

为什么我需要在模块中一次提供依赖   再一次在组件中定义它。这是愚蠢的。

并不总是正确的。如果您不想在外部暴露任何内容,则无需在组件中定义任何内容。暴露的替代方法是注入。

@Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
    fun inject(activity: MainActivity)
}

您在此处没有公开任何内容,但仍可以通过注入从容器中获取活动上下文。

现在让我们进行范围界定。

作用域确定是在容器内提供“本地单例”的方法。范围内的依赖项仅在容器内创建一次。例如,您的PerActivity范围。作用域组件仅接受具有相同作用域的模块。例如:

@PerActivity
@Component(dependencies = [AppComponent::class],
        modules = [ActivityModule::class])
interface ActivityComponent{
    fun inject(activity: MainActivity)
}

相应的模块也只能使用PerActivity进行作用域。

class ActivityModule(activity:Activity) {
    @PerActivity
    @Provides
    fun provideActivity() = activity
}

模块中定义的任何其他范围与预期组件的范围都不相同将导致编译错误。也不允许使用多个范围。

对于组件依赖性,可以使用use dependenciessubcomponents。如果使用了依赖关系,则子级所需的任何依赖项都必须由父级公开。在上述情况下,如果ActivityComponent需要活动上下文,则AppComponent必须定义一个返回它的函数。在子组件中,只需在组件中定义子组件,相关性将在内部解决。

我已经写了一个学习匕首2的小指南。如果您有兴趣,可以去看看。 https://medium.com/tompee/android-dependency-injection-using-dagger-2-530aa21961b4 https://medium.com/tompee/dagger-2-scopes-and-subcomponents-d54d58511781

答案 1 :(得分:1)

  

为什么我需要一次在模块中提供依赖项,而又在组件中定义它。这是愚蠢的。

我同意,但是不要因为这个事实而灰心,因为一旦您掌握了它,您就会学会欣赏它并真正利用它。我已经使用2.2版本一段时间了,没有任何问题。我只需要定义一个注释,添加一对附加的依赖项(其中有AutoDagger,它负责该 component功能),并使用以下结构:

internal static string GetPropertyAttributeShortName(string propertyName)
{
    return ((DisplayAttribute)(typeof(SensorsModel).GetProperty(propertyName).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName;
}

DaggerScope.java

/*   Dagger   */
implementation "com.google.dagger:dagger:2.2"
// Fix: github.com/rharter/auto-value-gson/issues/43#issuecomment-219994018
kapt 'com.squareup:javapoet:1.9.0'
kapt "com.google.dagger:dagger-compiler:2.2"
compileOnly 'org.glassfish:javax.annotation:10.0-b28'

/*  Autodagger   */
kapt "com.github.lukaspili.autodagger2:autodagger2-compiler:1.1"
implementation "com.github.lukaspili.autodagger2:autodagger2:1.1"

YourApp.kt

@Retention(RetentionPolicy.RUNTIME)
@Scope
@interface DaggerScope {
}

SomeActivity.kt

@AutoComponent(modules = [YourApp.Module::class])
@AutoInjector
@DaggerScope
class YourApp : Application() {
    ...

    @Singleton @dagger.Module
    inner class Module(private val app : YourApp) {
        @Provides @AutoExpose(YourApp::class) fun application(): Application = app
        @Provides @AutoExpose(YourApp::class) fun context(): Context = app
        ...
        // Stuff like your database or base service can go here
    }
}

您也可以使用@AutoComponent(dependencies = [YourApp::class], modules = [SomeActivity.Module::class]) // you are free to add other modules here @AutoInjector @DaggerScope class SomeActivity : AppCompatActivity() { ... @dagger.Module inner class Module() { @Provides @AutoExpose(SomeActivity::class) fun something(): Something { return some way of creating Something } /* specific deps for SomeAcitivity's actions, like specific services. You can also access DAOs as you've got access to the DB */ } } 代替Fragment来模仿此结构。

希望这对您有帮助!