我们在使用 Dagger 时真的需要 viewModelFactories 和 viewmodelProviders 吗?
Do we really need viewModelFactories and viewmodelProviders when using Dagger?
所以我正在使用 Dagger 开发一些示例 MVVM 项目。我有一个像这样的视图模型工厂:
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)
}
}
}
视图模型工厂模块
@Module
abstract class ViewModelFactoryModule {
@Binds
abstract fun bindViewModelFactory(viewModelFactory: DaggerViewModelFactory): ViewModelProvider.Factory
}
我有一个 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) {...
所以我可以使用像这样的视图模型工厂将我的视图模型注入到我的 activity 中:
@Inject
lateinit var viewModelFactory: DaggerViewModelFactory
private lateinit var takePicturesViewModel: TakePicturesViewModel
.
.
.
takePicturesViewModel = ViewModelProviders.of(this, viewModelFactory).get(TakePicturesViewModel::class.java)
或者根本没有视图模型工厂,像这样:
@Inject
lateinit var takePicturesViewModel: TakePicturesViewModel
两种方式都有效,所以我想知道哪种方式是正确的,如果使用 Dagger 允许我注入一个视图模型而不需要 viewmodelfactory,是否有充分的理由保留它?或者我应该只是摆脱这个 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?
两种方式的工作方式不同。尝试使用 ViewModel 中存储的数据旋转屏幕,您就会看到。
Dagger 可以创建 ViewModel,这是您在通用 ViewModelFactory 中使用的。这些视图模型应该是无范围的,因此您每次都会创建一个新的 ViewModel。 Android 支持库将缓存该 ViewModel 并在旋转后重用它,以便您可以保留数据——工厂方法被调用一次,并且只会创建一个 ViewModel(每个生命周期)。您保留数据,一切都按预期运行。
如果您使用 Dagger 直接注入您的 ViewModel,上述 none 将适用。与任何其他依赖项一样,一个新的 ViewModel 将在创建时被注入,导致每次使用它时都会创建一个 ViewModel——您不仅会使用存储在其中的数据,您将无法与片段共享状态要么。
当然,您 可以 将范围应用于 ViewModel,但该范围应该比 Activity 实例(以保持旋转之间的状态)更长寿,但是不再活到屏幕可见。因此,您既不能将其范围限定到 activity 也不能限定到应用程序生命周期。您可以通过在两者之间引入一个新范围来让它工作,但此时您将重新发明 ViewModel 库。
tl;dr 注入并使用工厂,否则您将获得 confusing/wrong ViewModel 实现。
所以我正在使用 Dagger 开发一些示例 MVVM 项目。我有一个像这样的视图模型工厂:
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)
}
}
}
视图模型工厂模块
@Module
abstract class ViewModelFactoryModule {
@Binds
abstract fun bindViewModelFactory(viewModelFactory: DaggerViewModelFactory): ViewModelProvider.Factory
}
我有一个 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) {...
所以我可以使用像这样的视图模型工厂将我的视图模型注入到我的 activity 中:
@Inject
lateinit var viewModelFactory: DaggerViewModelFactory
private lateinit var takePicturesViewModel: TakePicturesViewModel
.
.
.
takePicturesViewModel = ViewModelProviders.of(this, viewModelFactory).get(TakePicturesViewModel::class.java)
或者根本没有视图模型工厂,像这样:
@Inject
lateinit var takePicturesViewModel: TakePicturesViewModel
两种方式都有效,所以我想知道哪种方式是正确的,如果使用 Dagger 允许我注入一个视图模型而不需要 viewmodelfactory,是否有充分的理由保留它?或者我应该只是摆脱这个 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?
两种方式的工作方式不同。尝试使用 ViewModel 中存储的数据旋转屏幕,您就会看到。
Dagger 可以创建 ViewModel,这是您在通用 ViewModelFactory 中使用的。这些视图模型应该是无范围的,因此您每次都会创建一个新的 ViewModel。 Android 支持库将缓存该 ViewModel 并在旋转后重用它,以便您可以保留数据——工厂方法被调用一次,并且只会创建一个 ViewModel(每个生命周期)。您保留数据,一切都按预期运行。
如果您使用 Dagger 直接注入您的 ViewModel,上述 none 将适用。与任何其他依赖项一样,一个新的 ViewModel 将在创建时被注入,导致每次使用它时都会创建一个 ViewModel——您不仅会使用存储在其中的数据,您将无法与片段共享状态要么。
当然,您 可以 将范围应用于 ViewModel,但该范围应该比 Activity 实例(以保持旋转之间的状态)更长寿,但是不再活到屏幕可见。因此,您既不能将其范围限定到 activity 也不能限定到应用程序生命周期。您可以通过在两者之间引入一个新范围来让它工作,但此时您将重新发明 ViewModel 库。
tl;dr 注入并使用工厂,否则您将获得 confusing/wrong ViewModel 实现。