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 version="1.0" encoding="utf-8"?>                                                    

布局格式参考上述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() {        @Override        public 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() {                @Override                public 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 {    @Override    protected 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() {        @Override        public 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() {                @Override                public 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的使用与原理

更多相关文章

  1. AndroidManifest.xml文件综合详解
  2. Activity的启动模式以及Intent的七大属性
  3. Android(安卓)DataBing详解
  4. Android开发–Intent-filter属性详解
  5. Android(安卓)Service的绑定 基础概念篇
  6. Android界面开发之样式定义(Defining Styles)
  7. android 启动 service 的两种方法
  8. Android属性动画之ObjectAnimator控制
  9. layout_weight属性图解

随机推荐

  1. 1024 小鹿自费给读者送书啦!
  2. COVID-19每日数据|04-09
  3. 【决战西二旗】|理解标准模板库STL(一)
  4. 我常用的10个Python实用小Trick
  5. 图解:什么是 JS 原型和原型链?
  6. Pandas进阶修炼120题同步视频现已登陆
  7. 【决战西二旗】|你真的懂快速排序?
  8. 词云图的几种制作方法评测,你pick哪款
  9. 动画:用动画给女朋友讲解 TCP 四次分手过
  10. 浅谈集群版Redis和Gossip协议