概述
说到Android MVVM,相信大家都会想到Google 2015年推出的DataBinding框架。然而两者的概念是不一样的,不能混为一谈。MVVM是一种架构模式,而DataBinding是一个实现数据和UI绑定的框架,是构建MVVM模式的一个工具。
之前看过很多的文章都有简单的介绍MVVM架构如何使用的,但是呢自己总是一知半解的状态,今天通过再次的学习,终于对MVVM有了一个更深刻的理解,现在就来分享下自己的心得。
MVC、MVP、MVVM
首先让我们来了解下Android中常见的开发模式。
MVC
View:XML布局文件。 Model:实体模型(数据的获取、存储、数据状态变化)。 Controller:对应于Activity,处理数据、业务和UI。
从上图可以看出,Android本身的设计还是符合MVC架构的,但是Android中纯粹作为View的XML视图功能太弱,我们大量处理View的逻辑只能写在Activity中,这样Activity就充当了View和Controller两个角色并且耦合度也很高,直接导致Activity中的代码大爆炸。
相信大多数Android开发者都遇到过一个Acitivty数以千行的代码情况吧!所以,因此这个MVC结构最终其实只是一个Model-View(Activity:View&Controller)的结构。
MVP
Model: 依然是实体模型。
View: 对应于Activity和XML,负责View的绘制以及与用户的交互。 Presenter: 负责完成View与Model间的交互和业务逻辑。
上面我们说到了mvc中的activity充当了View和Controller的角色,而MVP很好的解决了这个问题,核心理念是通过一个抽象的View接口(不是真正的View层,也就是我们常用的VIewInterface)将Presenter与真正的View层进行解耦。
Persenter持有该View接口,对该接口进行操作,而不是直接操作View层。这样就可以把视图操作和业务逻辑解耦,从而让Activity成为真正的View层。有一定的好处就是团队协作,便于开发。
不过它也有弊端:
该模式有点像分模块分包处理一样,每一个模块中都会存在大量的presenter、view、model、viewInterface这样的包名,当业务量过大时,代码量依旧是庞大臃肿,而且每个模块之间如果有相同的功能或者网络请求的时候,并不能进行代码复用,只能在不同的包中copy一次相同的代码。如果说要更新UI操作的时候需要改动的是V和P层,通过在V层添加接口在P层中实现接口来达到更新UI的效果,在一定程度上还是存在了耦合性的。
MVVM
Model: 实体模型。
View: 对应于Activity和XML,负责View的绘制以及与用户交互。 ViewModel: 负责完成View与Model间的交互,负责业务逻辑。
其实关于MVVM,之前有过错误的理解,一度认为是四层,当然现在肯定不会这样认为了。
从这个图和上面的两个图相比,明显的感觉到了这个图比之前的更为简单更为方便。其实MVVM就是MVP的升级版,MVVM的目标和思想与MVP类似,利用数据绑定(Data Binding)、依赖属性(Dependency Property)、命令(Command)、路由事件(Routed Event)等新特性,打造了一个更加灵活高效的架构。
Google在2015年就提出了要使用这种框架,那我们来看看它的神奇之处。
databinding顾名思义就是数据绑定,通过使用databinding来把数据和UI页面进行关联。
View
View层做的就是和UI相关的工作,我们只在XML、Activity和Fragment写View层的代码,View层不参与业务逻辑,也就是我们在Activity不写业务逻辑和业务数据相关的代码,更新UI通过数据绑定实现,尽量在ViewModel里面做(更新绑定的数据源即可),Activity要做的事就是初始化一些控件(如控件的颜色,添加RecyclerView的分割线),View层可以提供更新UI的接口(但是我们更倾向所有的UI元素都是通过数据来驱动更改UI),View层可以处理事件(但是我们更希望UI事件通过Command来绑定)。 简单地说:View层不做任何业务逻辑、不涉及操作数据、不处理数据,UI和数据严格的分开。
ViewModel
ViewModel只做和业务逻辑和业务数据相关的事,不做任何和UI相关的事情,ViewModel 层不会持有任何控件的引用,更不会在ViewModel中通过UI控件的引用去做更新UI的事情。 ViewModel就是专注于业务的逻辑处理,做的事情也都只是对数据的操作(这些数据绑定在相应的控件上会自动去更改UI)。 与此同时DataBinding框架支持双向绑定,可以通过双向绑定获取View层反馈给ViewModel层的数据,并对这些数据上进行操作。 关于对UI控件事件的处理,我们也希望能把这些事件处理绑定到控件上,并把这些事件的处理统一化,为此我们通过BindingAdapter对一些常用的事件做了封装,Command会把你可能需要的数据带给你,这使得我们在ViewModel层处理事件的时候只需要关心处理数据就行了。 强调:ViewModel 不做和UI相关的事。
Model
model层和mvp、mvc中的model没有什么区别,定义一个实体类进行数据的获取和存储而已 最后:Model只是一个实体类
敲黑板了,敲黑板了。重点来了
MVVM的编译方式和其他模式不同,它是实时编译的,所以我经常遇到一些莫名奇妙的问题。
PS:
1、BR类不存在(BR类生成跟我们所说的R文件是一样的性质),当我第一次使用的时候我方了,正是因为他实时编译的特性让我懵逼了。不过后面发现其实在日志的最后都会告诉你具体的原因了,大部分情况都是xml类中写错了,所以要注意了哦。
2、控件上没有值,控件没有值看你数据源有没有问题或者数据源有没有传递进去
目前遇到的也就是这些问题。
下面聊聊使用心得
1、首先我们在xml中写好相对应的界面和数据绑定关系
2、然后再Activity将页面和数据绑定起来
HomeLoanActBinding binding = DataBindingUtil.setContentView(this, R.layout.home_loan_act);
Intent intent = getIntent();
loanCtrl = new LoanCtrl(binding.apply, intent.getStringExtra(BundleKeys.LOANMONEY), intent.getStringExtra
(BundleKeys.LOANLIMIT), intent.getStringExtra(BundleKeys.REALMONEY), intent.getStringExtra(BundleKeys.FEE), intent.getStringExtra(BundleKeys
.CARDNAME), intent.getStringExtra(BundleKeys.CARDNO), intent.getStringExtra(BundleKeys.CARDID));
binding.setViewCtrl(loanCtrl);
HomeLoanActBinding binding = DataBindingUtil.setContentView(this, R.layout.home_loan_act);
通过DataBindingUtil将xml文件和activity进行关联起来,实现页面的绑定。注意
HomeLoanActBinding的生成规则是当前的activity命名加上Binding的形式。如:TestActivity生成的Binding就是TestActivityBinding.
binding.setViewCtrl(loanCtrl);
这个setViewCtrl就是将数据绑定,通过这样的两步我们就将数据和页面进行关联。
上面说到了LoanCtrl,当然他有一个自己的实体类LoanVM,这个就是我们所谓的Model类了,在这个类中我们通过使用databind的一些注解来设置一些属性的值或者是效果。
可以理解为自己写的一个方法,通过bindingAdapter来进行绑定,然后再xml中通过app:xxx(就是@bindingadapter注解的那个值)来进行调用
特别值得一提的就是在set方法中调用notifyPropertyChanged来实现数据的刷新
public void setStepEnable(boolean stepEnable) {
this.stepEnable = stepEnable;
notifyPropertyChanged(BR.stepEnable);
}
获取你会问BR.stepEnable怎么来的,这个其实就是VM的属性值。set方法中能做的不仅如此,如果说有一些逻辑的判断也是可以在这个里面进行的处理的
public void setPhone(String phone) {
this.phone = phone;
checkPhoneInput();
notifyPropertyChanged(BR.phone);
}
private void checkPwdInput() {
if (TextUtil.isEmpty(pwd) || pwd.length() < 6) {
setEnable(false);
} else {
setEnable(true);
}
}
是不是很强大,之前就算是使用MVP的模式我们都需要在V层将这种逻辑先写出来,做到了真正的解耦。不过弊端就是需要你要熟悉它的用法和了解它的编译,能很好的解决bug。
其他关于MVVM的基本资料就请大家自行查阅资料咯。以上就是我对MVVM的一些心得总结。