MVVM实现数据双向绑定

Associate what you’ re trying to learn with what you already know. —— Daily English

这篇文章旨在通过一个Demo让我们对Android中的MVVM架构进行初步的认识。

MVVM与DataBinding的关系

很多同学会将这两者混为一谈,所以开始介绍之前,我们需要先理清楚这两者的关系。
MVVM和MVC、MVP一样,是项目中的架构设计思想;DataBinding是一种工具,它可以用于MVVM,也同样可以用于MVC和MVP。所以这两者是两回事,一个是架构设计思想,一个是工具。但是有一点,那就是Android中的MVVM一般都需要借助DataBinding来实现,这也是很多人将这两者混为一谈的原因。

MVVM简介

MVVM是更节省的设计模式,能实现双向的数据绑定。

须知

MVVM可以理解成M V VM。其中的M指的是Model层,也就是我们的JavaBean。V指的是VIew层,也就是我们具体的布局,如EditText等。VM指的是ViewModel层,它是Model层和View层的一个桥梁,也用来处理视图逻辑和业务逻辑。
简而言之,M还是Model,V还是View,VM就是ViewModel层。三者的关系大致如下图所示:
在这里插入图片描述
这个架构模式有如下两个特点

  1. 降低耦合:一个ViewModel层可以绑定不同的View层,当Model变化时View可以不变。
  2. 可重用性:可以把一些视图逻辑放在ViewModel层中,让很多View重用这些视图逻辑。

ViewModel相当于model层和View层的一个桥梁,当View层比如说一个EditText的值发生改变了,无需通过Activity,就直接可以改变JavaBean对应的属性值。Model层set一个值,也无需通过Activity,就可以直接改变页面上的值。

MVVM是有弊端的,一个是修改之后需要经常ReBuild,而且项目越大,ReBuild的时间也越长。另外也有三个原因会导致它的内存消耗比较大,这个会在介绍DataBinding的时候讲到(点击查看)。这也是有些公司不愿意用MVVM架构的原因。但是,MVVM为什么还会这么火呢,就是因为这种View和Model的双向绑定思想是值得我们学习的,也很可能是一种趋势。

什么是单向数据绑定,什么是双向数据绑定。

单向绑定是指View层(如EditText)上的数据改变会实时更新到Model层JavaBean中对应的属性值(如username)上。或者,Model层的数据改变会实时更新到View层上的显示,这样我们称之为单向的数据绑定。而双向绑定呢,是指Model层和View层,无论那层数据改变都会实时更新到对方,Model层数据改变会更新View,同样,View层数据改变会更新Model,这样就称之为双向的数据绑定。

项目实践

模拟一个登录的功能。

第一步,引入
在module的build.gradle文件中引入DataBinding

android {...// 添加DataBinding依赖dataBinding{enabled = true}
)

第二步,定义实体类

public class UserInfo {// 被观察的属性(切记:必须是public修饰符,因为是DataBinding的规范)public ObservableField name = new ObservableField<>();public ObservableField pwd = new ObservableField<>();
}

实体类也可以定义成原始的那种格式,添加get(),set()方法,也可以定义成被观察者属性的格式。只要注意两点,一个是被观察者属性,一个是有刷新属性的方法。这里就不做解释,对格式有疑问的同学请参考我另一篇讲DataBinding的文章(点击查看)。

第三步,定义布局

布局界面很简单
在这里插入图片描述
对应xml文件代码如下



布局格式参考上述XML即可。

这里我们发现中的variable是一个ViewModel的名称和具体路径,当然也可以直接是一个实体类。这也就是我们为什么说DataBinding其实也可以用在MVC或MVP架构当中,因为这篇文章讲的是MVVM的架构,所以这里定义一个专门处理登录逻辑的ViewModel,叫做LoginViewModel类。

其中如android:onClick="@{loginViewModel.loginClickListener}"loginViewModel就是标签下LoginViewModel的name。可以把这里的loginViewModel理解成一个对象,而loginViewModel.loginClickListener就是相当于调用这个对象中一个叫loginClickListener的public方法。

LoginViewModel的方法随即附上。

第四步,定义ViewModel

public class LoginViewModel {public UserInfo userInfo;public View.OnClickListener loginClickListener = new View.OnClickListener() {@Overridepublic void onClick(View v) {// 尝试1:view --> model单向绑定测试,改变EditText的值,查看bean中的对应属性值是否发生变化。
//            Log.e("owen >>> ", userInfo.name.get() + "--" + userInfo.pwd.get());// 尝试2:model --> view单向绑定测试,Model层属性的变更,也会改变View层的显示
//            userInfo.name.set("Owen");
//            userInfo.pwd.set("0410");// 尝试3:模拟网络请求new Thread(new Runnable() {@Overridepublic void run() {if ("Owen".equals(userInfo.name.get()) && "123".equals(userInfo.pwd.get())) {Log.e("Owen >>> ", "登录成功!");} else {Log.e("Owen >>> ", "登录失败!");}}}).start();}};
}

注意LoginViewModel 类中的属性名userInfologinClickListener 是要和xml布局中如android:onClick="@{loginViewModel.loginClickListener}"的名称对应上。可以通过ctrl+左键点击跳转验证。

第五步,Rebuild Project
Rebuild完成后,会在data_binding_base_class_source_out目录下生成以[布局名]Binding.java文件,这里我们的布局叫activity_main,所以生成了一个名为ActivityMainBinding的Java类文件。目录的具体位置如下图所示:
在这里插入图片描述
有了它,我们就可以做绑定操作了。

最后一步,书写代码绑定

在Activity中创建ActivityMainBinding对象

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 1、必须先ReBuilder,2、书写代码绑定ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);new LoginViewModel(binding);}
}

通过构造方法传入LoginViewModel进行绑定

 public LoginViewModel(ActivityMainBinding binding) {userInfo = new UserInfo();// 将ViewModel和View进行绑定,通过DataBinding工具。binding.setLoginViewModel(this);}

最后LoginViewModel的完整代码如下:

public class LoginViewModel {public UserInfo userInfo;public LoginViewModel(ActivityMainBinding binding) {userInfo = new UserInfo();// 将ViewModel和View进行绑定,通过DataBinding工具。binding.setLoginViewModel(this);}public View.OnClickListener loginClickListener = new View.OnClickListener() {@Overridepublic void onClick(View v) {// 尝试1:view --> model单向绑定测试,改变EditText的值,查看bean中的对应属性值是否发生变化。
//            Log.e("owen >>> ", userInfo.name.get() + "--" + userInfo.pwd.get());// 尝试2:model --> view单向绑定测试,Model层属性的变更,也会改变View层的显示
//            userInfo.name.set("Owen");
//            userInfo.pwd.set("0410");// 尝试3:模拟网络请求new Thread(new Runnable() {@Overridepublic void run() {if ("Owen".equals(userInfo.name.get()) && "123".equals(userInfo.pwd.get())) {Log.e("Owen >>> ", "登录成功!");} else {Log.e("Owen >>> ", "登录失败!");}}}).start();}};
}

尝试代码依次开启,做测试
尝试1:在界面上输入用户名,密码,点击登录,查看log发现UserInfo中的两个属性值已经被改变。证明View --> Mode单向绑定是Ok的。
尝试2:程序运行后,直接点击登录,发现界面上的EditText上的值已经更改。证明Model --> View的单向绑定也是成功的。
尝试3:模拟网络登录。

这就是我们在业务中用到的MVVM,我们发现在Activity中什么事情都不用干,但是我们必须有一个VM来作为V和M的桥梁来沟通。我们现在不需要在Activity中做很多复杂的东西,这就是架构MVVM的思想。你学到了吗?


文中Demo下载地址。

Android 架构设计模式系列文章索引

MVC架构设计与经典的三层模型

MVVM实现数据双向绑定

DataBinding的使用与原理


架构师系列文章引导页


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部