gpt4 book ai didi

android - dagger2 和 android : load module which injects viewmodel on a map

转载 作者:行者123 更新时间:2023-11-29 18:44:15 25 4
gpt4 key购买 nike

我已经开始使用 Dagger2,所以还有很多东西要学。我想知道是否有人可以指出正确的方向。

因此,我创建了一个模块来注册我的 Activity 使用的 View 模型。它看起来像这样:

@Module
abstract class ViewModelModule {
@Binds
internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

@Binds
@IntoMap
@ViewModelKey(MainActivityViewModel::class)
internal abstract fun bindMainActivityViewModel(viewModel: MainActivityViewModel): ViewModel

@Binds
@IntoMap
@ViewModelKey(ShowDetailsViewModel::class)
abstract fun bindShowDetaislViewModel(viewModel: ShowDetailsViewModel): ViewModel
}

ViewModelKey 是一个简单的辅助注释类,如下所示:

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey (val value: KClass<out ViewModel>) {
}

ViewModelModule 由我的主要应用组件加载(用于创建应用):

@Singleton
@Component(
modules=[
AndroidSupportInjectionModule::class,
AppModule::class,
DatabaseModule::class,
NewsServiceModule::class,
JobBindingModule::class,
ViewModelModule::class,
PreferencesModule::class,
ActivityBindingModule::class
]
)
interface AppComponent: AndroidInjector<MyApp> {
@Component.Builder
abstract class Builder: AndroidInjector.Builder<MyApp>()
}

下面是 ActivityBindingModule 的代码,负责设置子组件(在本例中是我的应用程序使用的 Activity ):

@Module
abstract class ActivityBindingModule {
@ActivityScoped
@ContributesAndroidInjector()
internal abstract fun mainActivity(): MainActivity

@ActivityScoped
@ContributesAndroidInjector
internal abstract fun showDetailsActivity(): ShowDetailsActivity
}

在内部,每个 Activity 都使用如下代码实例化 View 模型(从 onCreate 方法中调用):

//view model code
_viewModel = ViewModelProviders.of(this, viewModelFactory)[ShowDetailsViewModel::class.java]

并且,如您所料,viewModelFactory 被注入(inject)为字段:

@Inject lateinit var viewModelFactory: ViewModelProvider.Factory

两个 View 模型都具有外部依赖项,这些依赖项设置在顶级应用程序组件引用的其他模块上。

并且,为了完整起见,这是我的 View 模型工厂的代码:

@Singleton
class ViewModelFactory @Inject constructor(private val viewModels: MutableMap<Class<out ViewModel>, Provider<ViewModel>>) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T
= viewModels[modelClass]?.get() as T

此代码有效,但似乎还可以改进。阅读文档后,我的印象是我可以重构我的 ViewModule 以便它简单地实例化我的 ViewModelFactory 并将每个 View 模型声明移动到单独的模块中(这样它们中的每一个都只能在“正确的” Activity 中注入(inject))。

为了对此进行测试,我首先将 ShowDetailsViewModel 移动到一个只有一个条目的新模块中:

@Module
internal abstract class DetailsModule {
@Binds
@IntoMap
@ViewModelKey(ShowDetailsViewModel::class)
abstract fun bindShowDetaislViewModel(viewModel: ShowDetailsViewModel): ViewModel

}

之后,ViewModelModule 看起来像这样:

@Module
abstract class ViewModelModule {
@Binds
internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

@Binds
@IntoMap
@ViewModelKey(MainActivityViewModel::class)
internal abstract fun bindMainActivityViewModel(viewModel: MainActivityViewModel): ViewModel
}

并且我已经更新了 ActivityBindingModule 以便看起来像这样:

@Module
abstract class ActivityBindingModule {
@ActivityScoped
@ContributesAndroidInjector()
internal abstract fun mainActivity(): MainActivity

@ActivityScoped
@ContributesAndroidInjector(modules = [DetailsModule::class])
internal abstract fun showDetailsActivity(): ShowDetailsActivity
}

请注意,现在我正在将 DetailsModule(实例化 ShowDetailsViewModel)传递给应用于 ContributeAndroidInjector 注释>showDetailsActivity 方法,因为该 View 模型仅由该 Activity 使用。

现在,我肯定遗漏了一些东西,因为在这样做之后,我总是会遇到以下异常:

java.lang.IllegalStateException: ViewModelProviders.of(th…ilsViewModel::class.java] must not be null

如果我调试应用程序,我可以看到将 ShowDetailsViewModel 移动到它自己的模型中并没有在工厂使用的 map 上注册它(即 map 只有一个条目,对应于 MainActivityViewModel 在 ViewModelModule 中注册。

我认为将每个 View 模型的声明移动到子组件使用的每个模块中应该仍然允许它注册到由注册到顶级组件的模块注入(inject)的映射中。我错了吗?我缺少什么来完成这项工作?

谢谢。

最佳答案

问题在于 ViewModelFactory@Singleton 并且它不会获得您在子组件中添加的任何绑定(bind)。从您的工厂中删除范围或使其成为 @ActivityScoped(与 Activity 的 ViewModel 相同的范围)

Activity(@ActivityScoped)可以访问工厂(@Singleton),但是工厂(@Singleton)没有从较低范围 (@ActivityScoped) 使用或创建 ViewModel 的权限。因此,将工厂移动到相同的范围 (@ActivityScoped) 将允许它创建有问题的 View 模型。

关于android - dagger2 和 android : load module which injects viewmodel on a map,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52348783/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com