Android 重用ViewModels-每个将使用它的屏幕的状态
据此: ViewModel应该公开视图的状态,而不仅仅是 事件 我之所以重用viewmodel,是因为我需要多个视图的相同数据,但我怀疑它们使用相同的数据,但显示方式不同。例如,如果我有一个用户列表,第一视图显示他们,第二视图使用数据进行排序,第三视图显示一些标签,如果用户列表达到一定大小 如果我只公开数据(用户列表),视图将决定对其执行什么操作,除了我违反了体系结构之外,还很难进行测试,因为我需要模拟android,但我只想测试是否调用了某个方法,不管视图如何显示它 因此,我正在考虑解决方案,比如为使用viewmodel的每个视图创建一个状态类,这样viewmodel将更新状态,现在我可以轻松地测试状态是否发生变化 我这里的问题是,重用视图模型的视图越多,每个视图的状态就越多,我也不这么认为,想象一下,即使一次只能显示一个视图,该方法也会改变所有状态 为每个视图创建单独的视图模型对我来说就像复制代码一样,例如:Android 重用ViewModels-每个将使用它的屏幕的状态,android,mvvm,android-architecture-components,android-mvvm,Android,Mvvm,Android Architecture Components,Android Mvvm,据此: ViewModel应该公开视图的状态,而不仅仅是 事件 我之所以重用viewmodel,是因为我需要多个视图的相同数据,但我怀疑它们使用相同的数据,但显示方式不同。例如,如果我有一个用户列表,第一视图显示他们,第二视图使用数据进行排序,第三视图显示一些标签,如果用户列表达到一定大小 如果我只公开数据(用户列表),视图将决定对其执行什么操作,除了我违反了体系结构之外,还很难进行测试,因为我需要模拟android,但我只想测试是否调用了某个方法,不管视图如何显示它 因此,我正在考虑解决方案,
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的活动