如何将存储库从 Android 动态功能模块注入/提供到应用模块

问题描述

我正在调查我当前 Android 应用程序中的动态功能模块。

我的应用程序由一个应用模块、多个静态模块和一个动态功能模块组成。

我正在尝试将动态功能模块中声明的存储库类注入到我的一个静态模块中的存储库类中。

我有一个通用的共享模块,其中包含一个定义

API 的接口

我的动态功能模块有一个类似于这样的存储库类:-

class DynamicFeatureRepository @Inject constructor(private val applicationContext: Context) : MyExperimentable {

    override fun accessDynamicModuleRawData(): List<MyExperimentDO> {
        val myExperimentDOs = mutablelistof<MyExperimentDO>()
        applicationContext.resources.openRawResource(R.raw.data).use {
            val reader = BufferedReader(InputStreamReader(it))
            while (reader.ready()) {
                val columns = reader.readLine().split(",")
                myExperimentDOs.add(
                    MyExperimentDO(
                        myExperimentId = columns[0].toLong(),selected = columns[1].toBoolean(),myExperimentName = columns[2],myExperiment = columns[3]
                    )
                )
            }
        }

        return myExperimentDOs
    }

    override fun generate(data: String): Map<String,String> {

        return emptyMap()
    }
}

我有一个静态模块,它使用上述动态功能模块存储库

我相信 Dagger 子组件将允许我将此动态功能模块存储库注入到我的静态模块类中,但是我不知道如何实现这一点。

到目前为止,我在通用模块中声明了以下 Dagger 类:-

import dagger.Module
import dagger.Subcomponent
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent

@Subcomponent
interface MyExperimentComponent {
    fun inject(myExperimentable: MyExperimentable)

    @Subcomponent.Factory
    interface Factory {
        fun create(): MyExperimentComponent
    }
}

@InstallIn(SingletonComponent::class)
@Module(subcomponents = [MyExperimentComponent::class])
class SubcomponentsModule {}

在我的动态特征模块中,我有这个 Dagger 类:-

@InstallIn(SingletonComponent::class)
@Module
class ExperimentModule() {
    @Provides
    fun getMyExperiment(@ApplicationContext appContext: Context): MyExperimentable {
       return DynamicFeatureRepository(appContext)
    }
}

在我的静态模块中,我有这个 @Inject

@Inject
lateinit var myExperimentable: MyExperimentable

我的应用程序构建并运行,但是我的静态模块中的 @Inject 不满意,因为我的应用程序失败

kotlin.UninitializedPropertyAccessException: lateinit property myExperimentable has not been initialized

我哪里出错了?

我如何@Provide 我的一个静态模块的动态功能模块存储库

下面是我的静态模块中的“注入站点”:-

class MyRepository @Inject constructor(private val datastore: DataStore,private val workMonitor: WorkMonitor) {

    @Inject
    lateinit var myExperimentable: MyExperimentable

...

    fun accessDynamicModuleRawData() {
        val rawData = myExperimentable.accessDynamicModuleRawData()
        Timber.i("xxx ${rawData.size}")
    }
}

Android docs 中有这个突出显示的注意事项:-

注意:每当您想创建 应用组件。如果你需要创建一个普通的 gradle 模块 依赖于一个功能模块并且需要创建一个组件 取决于该功能模块中定义的组件,您可以使用 子组件照常。

这不是我的情况吗?我的静态模块需要/依赖于我的动态功能模块中定义的组件。这个评论让我相信我可以使用 Dagger 子组件来解决我的问题。如果这是真的“我如何”使用子组件来启用将我的 DFM 存储库注入到我的静态模块存储库中?

更新

我已将此 @EntryPoint 添加到我的应用模块中:-

@EntryPoint
@InstallIn(SingletonComponent::class)
interface MyExperimentableEntryPointInterface {

    fun getMyExperimentable(): MyExperimentable

}

这将允许我在我的目标存储库中使用它

val bar = EntryPoints.get(appContext,MyExperimentableEntryPointInterface::class.java).getMyExperimentable()

我遇到的问题是如何从我的 DFM“Provide”实现 MyExperimentable

在我的 DFM 中,我尝试过:-

@Module
@disableInstallInCheck
object DynamicFeatureRepositoryeModule {

    @Provides
    @Singleton
    fun provideDynamicFeatureRepository(): MyExperimentable {
        return DynamicFeatureRepository()
    }
}

但是我在构建时遇到此异常:-

error: [Dagger/MissingBinding] MyExperimentable cannot be provided without an @Provides-annotated method.

为了将 DFM 存储库的实例提供到我的应用中,我缺少什么?

更新的解决方

我设法使用 Dagger 并基于此 sample 我不喜欢的方面是这使用了反射

解决方法

为什么不在 MyExperimentable 类中添加 MyRepository 依赖项作为构造函数注入。通常,我们对活动/视图/片段进行字段注入。如果我们使用构造函数注入来实现,那么您将在编译时得到确切的错误原因。

可能是这样的:

class MyRepository @Inject constructor(private val datastore: DataStore,private val workMonitor: WorkMonitor,private val myExperimentable: MyExperimentable) {

    //@Inject
    //lateinit var myExperimentable: MyExperimentable

...

    fun accessDynamicModuleRawData() {
        val rawData = myExperimentable.accessDynamicModuleRawData()
        Timber.i("xxx ${rawData.size}")
    }
}