I am building an app with a dynamic feature.
To provide all the dependencies to the main module and the feature module I am using dagger 2. The feature component is depending on the main component and because of that, the feature component is having a different scope than the main component scope (@Singleton
in that case)
One of the interface injected in the main module are implemented on the feature module and provided by reflection in the main module. The implementation is also used in the feature module.
The problem that I have is that the instance provided in the main module is different from the one in the feature module (because of the scopes) but I would like to have just one instance provided with dagger.
Here some code and you can find the whole example project in github
Dagger configuration for the main module:
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 configuration for the feature module:
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
}
The interfaces TestC
and TestA
are injected in the MainActivity
The interfaces TestB
and TestA
are injected in the TestBroadcastReceiver
As expected the instance of the TestA
implementation is unique but for the implementation of the TestB
is not that way. As TestC
depends on TestB
the one injected in TestC
is different from the one injected in the TestBroadcastReceiver
with the @TestScope
annotation.
So running the example project that you can find here I get the following log output
Instances injected in the MainActivity
D/TestB: instance 40525431
D/TestC: instance 119319268
D/TestA: instance 60713805
Instances injected in the TestBroadcastReceiver
D/TestB: instance 219966227
D/TestA: instance 60713805
I would like to share the same instance of TestB
in both modules.
Any suggestion? Thanks in advance!
I was building two instances of the DaggerTestDependencyComponent
one in the Injector
and another different one when you are implementing TestC
The solution that I found was the following:
Create an object where I can instantiate the TestDependencyComponent
that will be shared with the Injector
and the TestCImplementation
object FeatureInjector {
val testDependencyComponent: TestDependencyComponent by lazy {
DaggerTestDependencyComponent.builder()
.testComponent(com.example.daggertest.dagger.Injector.testComponent)
.build()
}
}
Now I modified my feature Injector
like that:
object Injector {
lateinit var testDependencyComponent: TestDependencyComponent
@JvmStatic
internal fun getTestDependencyComponent(): TestDependencyComponent {
if (!::testDependencyComponent.isInitialized) {
testDependencyComponent = FeatureInjector.testDependencyComponent
}
return testDependencyComponent
}
}
And the TestCImplementation
as follow:
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()
}
}
}
Running the code now I am getting the same instance of the TestB