【发布时间】:2021-02-23 15:46:06
【问题描述】:
我正在研究我当前的 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 我不喜欢的方面是这采用了反射
【问题讨论】:
-
你能在哪里分享你的代码吗
@Inject lateinit var myExperimentable: MyExperimentable -
我很确定您不会将在运行时可能存在也可能不存在的东西注入到其他东西中。您只能手动继承到动态功能模块中,而不是相反。
-
实际上,您很可能需要动态功能模块中的组件依赖项
-
不,Hilt 不支持 DFM。 Hilt 只能看到开箱即用的应用程序中的内容。但是您可以使用 EntryPoints 访问器来获取 SingletonComponent,并从中继承。
标签: android dagger-2 dagger-hilt dynamic-feature-module