重用ViewModels-每个使用它的屏幕的状态

时间:2019-06-10 05:54:32

标签: android mvvm android-architecture-components android-mvvm

根据此article

  

ViewModel应该公开View的状态,而不仅仅是   事件。

我正在重用视图模型,因为我需要用于多个视图的相同数据,但我对此感到怀疑的是,它们使用相同的数据,但是它们以不同的方式显示 。例如,如果我有一个用户列表,则第一个视图显示他们第二个视图使用数据用于排序,如果用户列表达到特定大小,则第三视图会显示一些标签

如果我只公开数据(用户列表),并且视图将决定要执行的操作,除了违反架构外,还很难测试,因为我需要模拟android,但我只要测试是否调用了某个方法,视图的显示方式无关紧要。

所以我在考虑解决方案,例如为每个使用viewmodel的视图创建一个State类,以便该viewmodel更新状态,现在我可以轻松地测试状态是否发生变化。

我的问题是,重用视图模型的视图越多,每个视图的状态就越多,这在我看来也不是一件容易的事,只需想象一下即使一个视图中只有1个视图,该方法也会更改所有状态。时间可以显示。

为每个视图创建单独的视图模型就像为我复制代码一样,例如:ResetPasswordViewCreatePasswordView,它们都具有相同的过程,行为也几乎相同,所以为什么不重用viewmodel ? ...还是我应该?我在这里想念什么?

编辑(我当前的解决方案):

根据我的操作,我为每个片段/活动创建了单独的视图模型,因为尽管它们使用相同的数据,但它们表示的方式不同。这样,我就可以对表示逻辑进行单元测试,因为所有数据操作(特定于视图)都在视图模型上进行。

我确实共享视图模型,但是出于导航目的,示例是解释此视图的最佳方法(我在这里使用Koin作为我的依赖框架):

OnBoardingActivity

class OnBoardingActivity {

   var fullNameViewModel by viewModel<FullNameViewModel>()

   private fun initViewModels() {
      fullNameViewModel.stateShowEmail.observe(this, Observer {
         // do navigate to email because that's the next screen/fragment after FullNameFragment
      })
   }
}

FullNameFragment

class FullNameFragment {

   var viewModel by sharedViewModel<FullNameViewModel>() // notice that I share the view model from the activity here to have only 1 instance

   private fun initViews() {
      RxTextView.textChanges(etFirstName)
         .doOnNext { viewModel.setFirstName(it.toString()) }
         .subscribe()

     // ... set the other fields
   }

   private fun initViewModels() {
      viewModel.stateValidationFirstName.observe(this, Observer {
         when(it) { // validation
            is RequiredValidation -> // show some error/validation message
            else -> it is valid! remove any error/validation messages
         }
      })
   }
}

FullNameViewModel

class FullNameViewModel {

   val stateValidationFirstName = MutableLiveData<Validation>() // some validation object
   val stateShowEmail = SingleLiveEvent<Any>() // I'm using the hacky single live event here hehe

   fun setFullName() {
      // do the validations, some process and this can be easily test
      // like: stateValidationFirstName = RequiredValidation()

      stateShowEmail.call()
   }
}

1 个答案:

答案 0 :(得分:1)

通常,当文章引用视图时,它们并不意味着文字View类。他们是从建筑意义上讲的。

以MVVM为例。模型-视图-视图模型。

当我们谈论Android时,视图是ActivityFragmentView布局。

因此理想情况下,对于最合乎逻辑的集合,您应该有一个ViewModel

如果您有一个Activity和一个布局,但没有Fragment,那么有意义的是有一个ViewModel来覆盖Activity状态,其中包括其布局

如果您有一个Activity及其自己的布局和一个Fragment,则可能有两个ViewModel。一个用于Activity状态,另一个用于Fragment

我编写了一个示例应用程序,可能会有所帮助: https://github.com/DavidEdwards/mvvm-example

以具有基本Activity且除Fragment以外没有布局的示例为例。 ViewModel中会有一个Fragment(通常,这绝不是规则)。在此ViewModel中,您将有LiveData代表您的View的状态。当您想更改View的状态时,可以在ViewModel中更改状态,然后ViewModel会将更改传播到View。通常,我会使用出色的Android Databindings LibraryViewModel传递到我的布局中来完成此任务。

您可以看到有关hereherehere的示例。在此示例中,我通过观察游戏中玩家数量的状态来控制View的可见性。