Единичный экземпляр для разных прицелов с кинжалом 2

Проблема

Я создаю приложение с динамической функцией.

Чтобы обеспечить все зависимости для основного модуля и функционального модуля, я использую кинжал 2. Компонент функции зависит от основного компонента, и из-за этого компонент функции имеет область, отличную от области действия основного компонента (@Singleton в этом случае)

Один из интерфейсов, внедренных в основной модуль, реализован в функциональном модуле и обеспечивается отражением в основном модуле. Реализация также используется в функциональном модуле.

Проблема, с которой я столкнулся, заключается в том, что экземпляр, представленный в основном модуле, отличается от экземпляра в функциональном модуле (из-за возможностей), но я хотел бы иметь только один экземпляр с кинжалом.

Код

Вот код, и вы можете найти весь пример проекта в 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
}

Ожидаемый результат

Интерфейсы TestC а также TestA вводятся в MainActivity

Интерфейсы TestB а также TestA вводятся в 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 в обоих модулях.

Любое предложение? Заранее спасибо!

2 ответа

Решение

Я строил два экземпляра DaggerTestDependencyComponent один в Injector и еще один другой, когда вы реализуете TestC

Решение, которое я нашел, было следующее:

  • Создайте объект, в котором я могу создать экземпляр TestDependencyComponent это будет передано Injector и TestCImplementation

    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

TestDependencyComponent не может получить доступ к TestC из зависимости компонента от TestComponent, поскольку TestComponent не предоставляет TestC в своем общедоступном API. Если вы добавитеfun testC(): TestCon TestComponent, я ожидаю, что вы получите дублирующееся исключение привязки при обработке TestDependencyComponent. Оттуда вам нужно будет определить правильный способ предоставления экземпляра TestC.

Другие вопросы по тегам