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

Android 重用ViewModels-每个将使用它的屏幕的状态,android,mvvm,android-architecture-components,android-mvvm,Android,Mvvm,Android Architecture Components,Android Mvvm,据此: ViewModel应该公开视图的状态,而不仅仅是 事件 我之所以重用viewmodel,是因为我需要多个视图的相同数据,但我怀疑它们使用相同的数据,但显示方式不同。例如,如果我有一个用户列表,第一视图显示他们,第二视图使用数据进行排序,第三视图显示一些标签,如果用户列表达到一定大小 如果我只公开数据(用户列表),视图将决定对其执行什么操作,除了我违反了体系结构之外,还很难进行测试,因为我需要模拟android,但我只想测试是否调用了某个方法,不管视图如何显示它 因此,我正在考虑解决方案,

据此:

ViewModel应该公开视图的状态,而不仅仅是 事件

我之所以重用viewmodel,是因为我需要多个视图的相同数据,但我怀疑它们使用相同的数据,但显示方式不同。例如,如果我有一个用户列表,第一视图显示他们第二视图使用数据进行排序第三视图显示一些标签,如果用户列表达到一定大小

如果我只公开数据(用户列表),视图将决定对其执行什么操作,除了我违反了体系结构之外,还很难进行测试,因为我需要模拟android,但我只想测试是否调用了某个方法,不管视图如何显示它

因此,我正在考虑解决方案,比如为使用viewmodel的每个视图创建一个状态类,这样viewmodel将更新状态,现在我可以轻松地测试状态是否发生变化

我这里的问题是,重用视图模型的视图越多,每个视图的状态就越多,我也不这么认为,想象一下,即使一次只能显示一个视图,该方法也会改变所有状态

为每个视图创建单独的视图模型对我来说就像复制代码一样,例如:
ResetPasswordView
CreatePasswordView
,它们都有相同的过程,行为也几乎相同,所以为什么不重用视图模型呢。。。还是我应该?我错过了什么

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

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

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

船上活动

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
      })
   }
}
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
         }
      })
   }
}
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()
   }
}
class-OnBoardingActivity{
var fullNameViewModel by viewModel()
私有视图模型(){
fullNameViewModel.stateShowEmail.observe(此,观察者{
//请导航到电子邮件,因为这是FullNameFragment之后的下一个屏幕/片段
})
}
}
FullNameFragment

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
      })
   }
}
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
         }
      })
   }
}
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()
   }
}
类FullNameFragment{
var viewModel by sharedViewModel()//注意,我在这里共享活动中的视图模型,只有一个实例
私有视图(){
RxTextView.textChanges(etFirstName)
.doOnNext{viewModel.setFirstName(it.toString())}
.subscribe()
//…设置其他字段
}
私有视图模型(){
viewModel.stateValidationFirstName.observe(这个,观察者{
当(它){//
是否需要验证->//显示一些错误/验证消息
else->有效!删除所有错误/验证消息
}
})
}
}
全名视图模型

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
      })
   }
}
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
         }
      })
   }
}
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()
   }
}
类FullNameViewModel{
val stateValidationFirstName=MutableLiveData()//某些验证对象
val stateshowmail=SingleLiveEvent()//我在这里使用的是骇人的单一现场事件呵呵
fun setFullName(){
//做验证,一些过程,这可以很容易地测试
//比如:stateValidationFirstName=RequiredValidation()
stateShowEmail.call()
}
}

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

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

当我们谈论Android时,视图是
活动
片段
视图
布局

因此,理想情况下,对于大多数逻辑集,应该有一个
ViewModel

如果您有一个
活动
和一个布局,但没有
片段
,那么有一个
视图模型
来覆盖包含其布局的
活动
状态是有意义的

如果有一个
活动
具有自己的布局和一个
片段
,则可能有两个
视图模型
s。一个用于
活动
状态,一个用于
片段

我编写了一个示例应用程序,可能会有所帮助:

例如,有一个基本的
活动
,除了它的
片段
之外没有布局。在
片段
中会有一个
ViewModel
(通常,这绝不是规则)。在这个
ViewModel
中,您将拥有
LiveData
来表示您的
视图的状态。当您想要更改
视图的状态时,您可以更改
视图模型中的状态,并且
视图模型将更改传播到
视图中。我通常会通过使用优秀的工具将
ViewModel
传递到我的布局中来实现这一点


你可以看到一个例子,和。在本例中,我通过观察游戏中玩家数量的状态来控制
视图的可见性。

不要为每个视图创建ViewModel。相反,对于每个片段和/或活动。还是我误解了你的意思?到目前为止,我创建的每个视图都是一个视图模型。虽然某些视图使用相同的数据,但渲染方式不同。这意味着它们仍然有自己的状态,这就是为什么我为每个片段创建了不同的视图模型。根据我所做的,我为每个片段创建了不同的视图模型,但它们是
sharedViewModel
,因此实际的
ViewModel
仍在活动中。我这么做是因为我听了t的活动