Hilt - 将 类 作为接口注入

Hilt - inject classes as interfaces

假设我有两个接口和两个实现它们的 类。

interface ITest1 {
    fun doSomething()
}

interface ITest2 {
    fun doSomethingElse()
}

class Test1 @Inject constructor(): ITest1 {

    override fun doSomething() {
        println("Something")
    }
}
    
class Test2 @Inject constructor(): ITest2 {

    @Inject
    lateinit var test1: ITest1

    override fun doSomethingElse() {
        test1.doSomething()
        println("Something else ")
    }
}

如果我使用@Bind,我可以完成这项工作:

@Module
@InstallIn(SingletonComponent::class)
internal abstract class DependenciesBindings {
    @Singleton
    @Binds
    abstract fun bindTest1(test1: Test1): ITest1

    @Singleton
    @Binds
    abstract fun bindTest2(test2: Test2): ITest2
}

但我想在注入它们之前对 类 做一些配置。为此,我尝试使用 @Provide:

@Module(includes = [DependenciesBindings::class])
@InstallIn(SingletonComponent::class)
object Dependencies {

    @Singleton
    @Provides
    fun provideTest1(): Test1 {
        return Test1()
    }

    @Singleton
    @Provides
    fun provideTest2(): Test2 {
        return Test2()
    }
}

@Module
@InstallIn(SingletonComponent::class)
internal abstract class DependenciesBindings {
    @Singleton
    @Binds
    abstract fun bindTest1(test1: Test1): ITest1

    @Singleton
    @Binds
    abstract fun bindTest2(test2: Test2): ITest2
}

但这会使应用程序崩溃:

Caused by: kotlin.UninitializedPropertyAccessException: lateinit property test1 has not been initialized at Test2.getTest1(Test2.kt:8) at Test2.doSomethingElse(Test2.kt:11)

为什么会这样?

我希望在提供 Test1 时正确注入 ITest1,然后绑定到 ITest1 接口。

是否有解决方法可以使此工作正常进行?

通过使用 @Provides 方法,您可以自己构建实例,而不是使用 Dagger。因此,Dagger 将允许您在不调用 @Inject 注释方法或填充 @Inject 注释字段的情况下这样做,这样 getTest1 将在未初始化的字段上失败。

一个更常见的模式可能让 ITest2 的绑定注入一个 Test2 实例(毕竟,@Provides methods can take arguments from the graph),这允许 Dagger 创建 Test2 实例并允许您在返回之前对其进行操作:

@Module(/* no includes */)
@InstallIn(SingletonComponent::class)
object Dependencies {

    @Singleton
    @Provides
    fun provideTest1(test1: Test1): ITest1 {
        // manipulate test1
        return test1
    }

    @Singleton
    @Provides
    fun provideTest2(test2: Test2): ITest2 {
        // manipulate test2
        return test2
    }
}

如果您不能让 Dagger 直接创建您的 Test1 或 Test2——例如,如果您无法控制构造函数——您可以注入一个 MembersInjector<Test1> 并使用它来注入 @Inject 字段和方法。

@Module(includes = [DependenciesBindings::class])
@InstallIn(SingletonComponent::class)
object Dependencies {

    @Singleton
    @Provides
    fun provideTest1(injector: MembersInjector<Test1>): Test1 {
        val test1 = Test1()
        injector.injectMembers(test1)
        return test1
    }

    @Singleton
    @Provides
    fun provideTest2(injector: MembersInjector<Test2>): Test2 {
        val test2 = Test2()
        injector.injectMembers(test2)
        return test2
    }
}