1

问题

我正在构建一个具有动态功能的应用程序。

为了向主模块和功能模块提供所有依赖项,我使用的是 dagger 2。功能组件取决于主组件,因此,功能组件的范围与主组件范围不同(@Singleton在这种情况下)

在主模块中注入的接口之一是在功能模块上实现的,并由主模块中的反射提供。该实现也用于功能模块中。

我遇到的问题是主模块中提供的实例与功能模块中的实例不同(因为范围),但我希望只提供一个带有 dagger 的实例。

代码

这里有一些代码,你可以在github中找到整个示例项目

主模块的匕首配置:

TestModule.kt

@Module
class TestModule {

    @Provides
    @Singleton
    fun provideTestA() : TestA = TestAImplementation()

    private var testCProvider: TestC?= null

    @Provides
    @Singleton
    fun provideTestC(testComponent: TestComponent) : TestC {
        if(testCProvider != null) return testCProvider as TestC

        val provider = Class.forName("com.example.feature.services.TestCImplementation\$Provider").kotlin.objectInstance as TestC.Provider
        return provider
            .get(testComponent)
            .also { testCProvider = it }
    }
}

TestComponent.kt

@Singleton
@Component(modules = [TestModule::class])
interface TestComponent {
    fun inject(activity: MainActivity)

    fun provideTestA() : TestA
}

功能模块的 Dagger 配置:

TestDependencyModule.kt

@Module
class TestDependencyModule {

    @Provides
    @TestScope
    fun provideTestB(): TestB = TestBImplementation()

    @Provides
    @TestScope
    fun provideTestC(testB: TestB): TestC = TestCImplementation(testB)
}

TestDependencyComponent.kt

@TestScope
@Component(
    modules = [TestDependencyModule::class],
    dependencies = [TestComponent::class]
)
interface TestDependencyComponent {
    fun inject(receiver: TestBroadcastReceiver)

    fun testC(): TestC
}

预期结果

接口TestCTestA被注入MainActivity

接口TestBTestA被注入TestBroadcastReceiver

正如预期的那样,实现的实例TestA是唯一的,但对于 的实现TestB却不是这样。TestC取决于注入的那个与带有注释的TestB注入的TestC不同。TestBroadcastReceiver@TestScope

因此,运行您可以在此处找到的示例项目,我得到以下日志输出

注入的实例MainActivity

D/TestB: instance 40525431
D/TestC: instance 119319268
D/TestA: instance 60713805

注入的实例TestBroadcastReceiver

D/TestB: instance 219966227
D/TestA: instance 60713805

我想TestB在两个模块中共享相同的实例。

有什么建议吗?提前致谢!

4

2 回答 2

0

TestDependencyComponent 无法从对 TestComponent 的组件依赖项访问 TestC,因为 TestComponent 没有在其公共 API 上公开 TestC。如果您添加fun testC(): TestCTestComponent,我希望您在处理 TestDependencyComponent 时会得到一个重复的绑定异常。从那里您将需要确定提供 TestC 实例的正确方法。

于 2019-11-19T15:56:32.987 回答
0

当您实施时,我正在构建DaggerTestDependencyComponent一个在另一个不同的实例中的两个实例InjectorTestC

我找到的解决方案如下:

  • 创建一个对象,我可以在其中实例化将与和TestDependencyComponent共享的InjectorTestCImplementation

    object FeatureInjector {
    
        val testDependencyComponent: TestDependencyComponent by lazy {
            DaggerTestDependencyComponent.builder()
                .testComponent(com.example.daggertest.dagger.Injector.testComponent)
                .build()
        }
    }
    
  • 现在我Injector像这样修改了我的功能:

    object Injector {
    
        lateinit var testDependencyComponent: TestDependencyComponent
    
        @JvmStatic
        internal fun getTestDependencyComponent(): TestDependencyComponent {
            if (!::testDependencyComponent.isInitialized) {
                testDependencyComponent = FeatureInjector.testDependencyComponent
            }
            return testDependencyComponent
        }
    }
    
  • 如下TestCImplementation

    class TestCImplementation @Inject constructor(
        private val testB: TestB
    ) : TestC {
        override fun testCFun() {
            testB.testBFun()
            Log.d("TestC", "instance ${System.identityHashCode(this)}")
        }
    
        companion object Provider : TestC.Provider {
            override fun get(testComponent: TestComponent): TestC {
                return FeatureInjector.testDependencyComponent.testC()
            }
        }
    }
    

现在运行代码我得到了相同的实例TestB

于 2019-11-26T09:00:05.020 回答