android - 使用 Dagger 跨两个/或多个片段和一个活动共享 ViewModel
问题描述
好吧,正如我试图在标题中总结的那样,这里是细节。
我们有一个相对较大的应用程序,它使用 Dagger,但方式并不理想,所以我们决定开始编写测试,为此,我需要公开 Mockito 的依赖项,因此,我遇到了一个问题,开始使用单例工厂,仍然适用,并且有大量的教程可以解释这一点。
我们的应用程序有很多功能,使用单个活动和导航组件实现,单个活动有时有一个创建的视图模型,我们使用它在容器活动和使用导航填充的片段之间共享数据编辑。
我想不通的是以下内容,我如何使用匕首注入共享视图模型,每次调用@Inject
特定视图模型时返回相同的实例,我知道它可以通过范围完成,但我想不通,我有一个解释,我需要验证。(我将在下面提供我的代码)
我首先实现了我的 Singleton ViewModelFactory,如下所示:
@Singleton
class ViewModelFactory @Inject constructor(private val creators: Map<Class<out ViewModel>,
@JvmSuppressWildcards Provider<ViewModel>>) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
val creator = creators[modelClass] ?: creators.entries.firstOrNull {
modelClass.isAssignableFrom(it.key)
}?.value ?: throw IllegalArgumentException("unknown model class $modelClass")
try {
@Suppress("UNCHECKED_CAST")
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
然后我创建了提供 ViewModelFactory 和 ViewModel 的 ViewModelModule,如下所示:
@Module
abstract class ViewModelFactoryModule {
@Binds
abstract fun bindsViewModelFactory(viewModelFactory: ViewModelFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@EbMainScope
@ViewModelKey(EBMainContainerViewModel::class)
abstract fun bindEbMainViewModel(ebMainContainerViewModel: EBMainContainerViewModel): ViewModel
}
在你问之前,这是范围实现:
@Scope
@Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
annotation class EbMainScope
最后一步,这是我的活动/片段注入器模块:
@Module
abstract class ScreensBuildersModule {
@ContributesAndroidInjector
@EbMainScope
abstract fun contributeEbMainActivity(): EBMainActivity
@ContributesAndroidInjector
@EbMainScope
abstract fun contributeEbDashboardMainFragment(): EBDashboardMainFragment
}
当然,我在 AppComponent 中连接了所有内容,并且应用程序运行顺利,EbMainContainerViewModel
尽管我定义了范围,但仍有两个实例。
我的解释是,我实际上有两个不同的提供程序而不是一个,但我仍然不明白为什么,因为我将它标记为@Singleton
.
有人对此有解释吗?如果需要更多输入,请告诉我。
解决方案
我有同样的问题,但用这种方式解决它:
- 例如,我使用以下代码: https ://github.com/android/architecture-samples/tree/dagger-android
在我的片段(我想在其中使用共享视图模型)中,我使用它(它帮助了我):
private val viewModel by viewModels<SearchViewModel>({ activity as MainActivity }) { viewModelFactory }
而不是这个(如示例):
private val viewModel by viewModels<SearchViewModel> { viewModelFactory }
因为第一个参数是ownerProducer,所以我们在活动范围内创建一个 ViewModel 。
推荐阅读
- java - 在处理中使用 Java 绘制螺旋
- javascript - 尝试运行 wasm 函数时模块未定义错误
- c# - 使用 C# 在 Core 3 中的 EF 中模仿 DB 的模式
- heroku - 在 Netlify 站点上的自定义子域上获取“未找到”。将 Route53 与 Netlify 和 Heroku 上托管的子域一起使用
- julia - 定义了自定义“显示”时显示复合类型的默认打印
- sql - SQL Netezza - 如何将日期时间四舍五入到最近的小时
- openssl - 如何从 pem 文件生成 X509?
- python - PyMongo 整数溢出?不是整数?应该是<3k的巨大数字
- javascript - 如何在 jQuery 的可拖动元素中选择特定 ID
- swift - SwiftUI - 根据输入参数更改视图变量