【问题标题】:Do we really need viewModelFactories and viewmodelProviders when using Dagger?在使用 Dagger 时,我们真的需要 viewModelFactories 和 viewmodelProviders 吗?
【发布时间】:2020-02-09 22:28:50
【问题描述】:

所以我正在使用 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) {...

所以我可以使用这样的视图模型工厂将我的视图模型注入到我的活动中:

    @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的?

提前感谢您的任何建议。

问候

【问题讨论】:

标签: mvvm dagger-2 dagger android-viewmodel android-mvvm


【解决方案1】:

两种方式都有效,所以我想知道哪一种是正确的工作方式,如果使用 Dagger 允许我在不需要 viewmodelfactory 的情况下注入视图模型,是否有充分的理由保留它?或者我应该摆脱这个viewmodelfactory的?

两种方式的工作方式不同。尝试使用 ViewModel 中存储的数据旋转屏幕,您会看到。

Dagger 可以创建 ViewModel,这是您在通用 ViewModelFactory 中使用的。这些视图模型应该是无范围的,因此您每次都将创建一个新的 ViewModel。 Android 支持库将缓存该 ViewModel 并在轮换后重用它,以便您可以保留数据——工厂方法被调用一次,并且只会创建一个 ViewModel(每个生命周期)。您保留您的数据,一切都按预期运行。

另一方面,如果您使用 Dagger 直接注入您的 ViewModel,则上述任何一项都不适用。与任何其他依赖项一样,新的 ViewModel 将在创建时注入,导致每次使用时都会创建一个 ViewModel——您不仅会使用存储在其中的数据,而且无法与 Fragment 共享状态要么。

当然,您可以为 ViewModel 应用范围,但该范围应该比 Activity 实例的寿命更长(以保持旋转之间的状态),但不会比屏幕可见长。因此,您既不能将其范围限定为活动,也不能限定于应用程序生命周期。您可以通过在两者之间引入一个新范围来使其工作,但此时您将重新发明 ViewModel 库。


tl;dr 注入并使用工厂,否则你会得到一个令人困惑/错误的 ViewModel 实现。

【讨论】:

  • 随着 Hilt 的引入,现在您可以将 @ActivityRetainedScope 用于您的视图模型,它会在活动旋转时为您提供相同的实例。
  • 只要你使用androidx.ViewModel,我会坚持使用他们的工厂/方法来创建虚拟机等等。无论哪种方式,混合起来只会令人困惑且难以维护。如果你想创建自己的由 Dagger/Hilt 支持的 VM,你当然可以这样做。我只是说如果你想做自己的事情,就不要使用androidx.ViewModel
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-02
  • 1970-01-01
  • 2012-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多