android - 如何将 Android Dynamic Feature 模块中的存储库注入/提供到 App 模块中
问题描述
我正在调查我当前的 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 文档中,有这个突出显示的注意事项:-
注意:只要您想创建 ApplicationComponent 的子组件,就会出现此问题。如果您需要创建一个依赖于某个特性模块的常规 gradle 模块,并且需要创建一个依赖于该特性模块中定义的组件的组件,则可以照常使用子组件。
我的情况不就是这样吗?我的静态模块需要/依赖于我的动态功能模块中定义的组件。这个评论让我相信我可以使用 Dagger 子组件来解决我的问题。如果这是真的“如何”使用子组件将我的 DFM 存储库注入到我的静态模块存储库中?
更新
我已将此添加@EntryPoint
到我的 App 模块中:-
@EntryPoint
@InstallIn(SingletonComponent::class)
interface MyExperimentableEntryPointInterface {
fun getMyExperimentable(): MyExperimentable
}
这将允许我在我的目标存储库中使用它
val bar = EntryPoints.get(appContext, MyExperimentableEntryPointInterface::class.java).getMyExperimentable()
我遇到的问题是如何“ Provide
”从我的 DFM 中执行 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 实现了预期的结果,并将我的解决方案基于此示例 我不喜欢的方面是这采用了反射
解决方案
为什么不将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}")
}
}
推荐阅读
- mongodb - MongoDB查询以查找其字段值包含在给定字符串中的文档
- sql - Oracle regexp_substr 提取数据
- c - 在C中打印数组的唯一值
- html - 将 div 的高度设置为 100% 不会填满容器 div 的整个高度
- elasticsearch - 为每个过滤后的 elasticsearch 文档运行子查询
- python - 在 Google Colab 中显示动画
- c - 迭代一个长整数,然后将数字附加到 C 中的数组
- apache - 如何将一些 url 直接指向一个 www 文件夹,而将其他 url 传递给 apache2
- c++ - 在 C++ 中分别测量每个线程上花费的 CPU 时间
- camera - 适配智能手机摄像头导出黑体温度