实现一个简单的 Dagger2 示例

Implementing a simple Dagger2 sample

我是 Dagger2 的新手(我一直使用 Koin),我正在尝试实现一个简单的示例,但我真的不知道我错过了什么。这是我到目前为止得到的。

app.gradle:

ext.daggerVersion = '2.23.2'

implementation "com.google.dagger:dagger:$daggerVersion"
implementation "com.google.dagger:dagger-android-support:$daggerVersion"
kapt "com.google.dagger:dagger-android-processor:$daggerVersion"
kapt "com.google.dagger:dagger-compiler:$daggerVersion"

AppModule.kt:

@Module
class AppModule {
    @Provides
    @Singleton
    fun provideApplication(app: App): Application = app

    @Provides
    @Singleton
    fun provideTestOperator(testOperator: TestOperator) = testOperator

    @Provides
    @Singleton
    fun provideTestClass(testClass: TestClass) = testClass

}

AppComponent.kt:

@Singleton
@Component(modules = [
    AndroidInjectionModule::class,
    AppModule::class
])
interface AppComponent : AndroidInjector<App> {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(app: App): Builder
        fun build(): AppComponent
    }
}

TestClass.kt & TestOperator.kt 在同一文件中:

class TestClass @Inject constructor(private val testOperator: TestOperator) {
    fun getRandomValueFromCTest(): Int = testOperator.generateRandomNumber()
}

class TestOperator @Inject constructor() {
    fun generateRandomNumber(): Int = Random.nextInt()
}

App.kt:

class App : DaggerApplication() {
    override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
        return DaggerAppComponent.builder().application(this@App).build()
    }
}

MainActivity.kt:

class MainActivity : AppCompatActivity() {
    @Inject
    lateinit var testClass: TestClass

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onResume() {
        super.onResume()
        val x = testClass.getRandomValueFromCTest()
    }
}

Error: testClass == null

MainActivity 应该扩展 DaggerActivity,而不是 AppCompatActivity

AppModule.kt:提供应用上下文。无需为您的测试编写@singleton @provides* classes(会明白为什么)

@Module
class AppModule {
    @Provides
    @Singleton
    fun provideApplication(app: App): Context = app.applicationContext
}

AppComponent.kt@Component.Builder 已弃用 IIRC。使用 @Component.Factory。并将 AndroidInjectionModule::class 替换为 AndroidSupportInjectionModule::class,因为我们使用的是 dagger-android-support 和 android 的 *Compat* 内容。在此处引用一个名为 ActivityModule::class.

的新模块
@Singleton
@Component(modules = [
    ActivityModule::class
    AndroidSupportInjectionModule::class,
    AppModule::class
])
interface AppComponent : AndroidInjector<App> {

    @Component.Factory
    abstract class Factory : AndroidInjector.Factory<App>
}

TestClass.kt & TestOperator.kt:由于您通过编写@singleton 和@provides 方法来提供单例,我假设您希望它们是单例。只需用 @Singleton 注释 class 定义,dagger 就会处理它。无需编写@Provides 方法。

@Singleton
class TestClass @Inject constructor(private val testOperator: TestOperator) {
    fun getRandomValueFromCTest(): Int = testOperator.generateRandomNumber()
}

@Singleton
class TestOperator @Inject constructor() {
    fun generateRandomNumber(): Int = Random.nextInt()
}

App.kt:使用工厂而不是构建器,因为 @Component.Builder 已被弃用。

class App : DaggerApplication() {
    override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
        return DaggerAppComponent.factory().create(this)
    }
}

ActivityModule.kt: 为 dagger 提供一个模块来创建你的活动。

@Module
interface ActivityModule {

    @ContributesAndroidInjector
    fun provideMainActivity(): MainActivity
}

MainActivity.kt:最后,从DaggerAppCompatActivity扩展。

class MainActivity : DaggerAppCompatActivity() {

    @Inject
    lateinit var testClass: TestClass

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onResume() {
        super.onResume()
        val x = testClass.getRandomValueFromCTest()
    }
}

我相信这应该 运行 没有问题。如需更多参考,您可以查看此 sample and the new simpler docs at dagger.dev/android

您错过了实际的注入调用。

class MainActivity : AppCompatActivity() {
  @Inject
  lateinit var testClass: TestClass

  override fun onCreate(savedInstanceState: Bundle?) {
      AndroidInjection.inject(this)
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)
  }