问题描述
因此,我正在使用Dagger进行一些示例MVVM项目.我有一个像这样的viewmodel工厂:
So I was working on some sample MVVM project using Dagger. I have a viewmodel factory that goes like this:
class DaggerViewModelFactory @Inject constructor(private val viewModelsMap: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>) :
ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
val creator = viewModelsMap[modelClass] ?:
viewModelsMap.asIterable().firstOrNull {
modelClass.isAssignableFrom(it.key)
}?.value ?: throw IllegalArgumentException("unknown model class $modelClass")
return try {
creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
viewmodel工厂模块
A viewmodel factory module
@Module
abstract class ViewModelFactoryModule {
@Binds
abstract fun bindViewModelFactory(viewModelFactory: DaggerViewModelFactory): ViewModelProvider.Factory
}
我有一个ViewModelModule:
I got a ViewModelModule:
@Module
abstract class MyViewModelModule {
@Binds
@IntoMap
@ViewModelKey(TakePicturesViewModel::class)
abstract fun bindTakePictureViewModel(takePicturesViewModel: TakePicturesViewModel): ViewModel
}
类似这样的组件:
@PerActivity
@Subcomponent(modules = [ActivityModule::class, ViewModelFactoryModule::class, MyViewModelModule::class])
interface ActivityComponent {
fun inject(mainActivity: MainActivity)
}
这样的视图模型:
class TakePicturesViewModel @Inject constructor(app: Application): AndroidViewModel(app) {...
所以我可以使用这样的视图模型工厂将我的视图模型注入到我的活动中:
So I can either inject my viewmodel in my activity using a view model factory like this:
@Inject
lateinit var viewModelFactory: DaggerViewModelFactory
private lateinit var takePicturesViewModel: TakePicturesViewModel
.
.
.
takePicturesViewModel = ViewModelProviders.of(this, viewModelFactory).get(TakePicturesViewModel::class.java)
或者根本没有viewmodel工厂,就像这样:
Or with not viewmodel factory at all, like this:
@Inject
lateinit var takePicturesViewModel: TakePicturesViewModel
两种方法都可以工作,所以我想知道哪种方法是正确的,如果使用Dagger允许我在不需要viewmodelfactory的情况下注入viewmodel,是否有充分的理由保留它?还是应该摆脱掉这个viewmodelfactory?
Both ways work, so I was wondering which one is the right way to work, if using Dagger allows me to inject a viewmodel without needing a viewmodelfactory, is there a good reason to keep it?, or should I just get rid of this viewmodelfactory?
预先感谢您的任何建议.
Thanks in advance for any advice.
问候
推荐答案
两种方法的工作方式不同.尝试旋转屏幕并使用ViewModel中存储的数据,您会看到.
Both ways work differently. Try rotating your screen with stored data in your ViewModel and you'll see.
Dagger可以创建ViewModel,这是您在该通用ViewModelFactory中使用的.这些视图模型应该不受作用域限制,因此您将每次创建一个新的ViewModel. Android支持库将缓存该ViewModel并在旋转后重新使用它,这样您就可以保持数据调用工厂方法一次,并且只会创建一个ViewModel(每个生命周期).您保留数据,一切都会按预期进行.
Dagger can create the ViewModel, which is what you make use of in that generic ViewModelFactory. Those view models should be unscoped, thus you'll be creating a new ViewModel every single time. The Android support library will cache that ViewModel and reuse it after rotation so that you can keep your data—the factory method gets called once and there will only ever be one ViewModel created (per lifecycle). You keep your data and everything behaves as expected.
另一方面,如果您使用Dagger直接注入ViewModel,则上述任何方法均不适用.像任何其他依赖项一样,新的ViewModel将在创建时注入,导致每次使用ViewModel时都会创建它-您不仅将使用存储在其中的数据,而且将无法与片段共享状态要么.
If on the other hand you use Dagger to inject your ViewModel directly none of the above will apply. Like any other dependency, a new ViewModel will be injected on creation, leading to a ViewModel being created every single time it is used—you'll not only use the data stored in it, you won't be able to share state with fragments either.
您当然可以 将范围应用于ViewModel,但是该范围的生存期应比Activity实例更长(以保持旋转之间的状态),但不能生存超过屏幕可见的时间.因此,您既不能将其范围限制在活动范围内,也不能将其范围限制在应用程序生命周期中.您可以通过在两者之间引入新的作用域来使其正常工作,但此时,您将重新发明ViewModel库.
Of course you could apply a scope to the ViewModel, but that scope should be longer lived than the Activity instance (to keep state between rotations), but no longer lived than the screen is visible. So you can neither scope it to the activity nor to the application lifecycle. You can get it to work by introducing a new scope in-between, but at this point you'd be reinventing the ViewModel library.
tl; dr 注入并使用工厂,否则将获得令人困惑/错误的ViewModel实现.
tl;dr Inject and use the factory or you'll get a confusing/wrong ViewModel implementation.
这篇关于使用Dagger时,我们真的需要viewModelFactories和viewmodelProviders吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!