前言:什么叫架构模式?
架构模式是一种通用的、可重用的解决方案,用于使程序实现模块化,做到模块内部的高聚合和模块之间的低耦合。实现程序开发过程中,开发人员只需要专注某个模块,提高程序开发的效率,同时也实现快速定位问题和需求变动时减少代码修改。
MVVM架构模式
MVVM在MVP的基础上加入了双向绑定,使View能够感知ViewModel中的数据变化,ViewModel能够感知View数据的变化。
视图层: Android的xml布局文件和Activity/Fragment文件等UI相关界面。
业务层: ViewModel 是 UI 的数据提供者。它不直接请求数据,而是通过 Repository 来管理数据。ViewModel 也不直接引用 View,它通过 LiveData 或其他观察者模式来通知 UI 数据的变化。
数据层: 数据层Model指的是,数据管理模块,这包括了数据的获取,处理,存储等。
MVVM使用实例
使用MVVM标准架构实现一个简易的登录界面(模拟网络判断)的Demo,方便更具体深入的了解MVVM架构模式。
项目结构
注意:当vm的包名路径需要小写,如果改成VM大写命名layout生成的BindingImpl.java是导入不了这个viewMdoel文件的路径然后程序就一直无法运行!!!
Model代码
package com.cxj.mvvm_demo.m;
public class Model {
public boolean login(String account, String pwd) {
return "admin".equals(account) && "123456".equals(pwd);
}
}
View代码
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.cxj.mvvm_demo.vm.ViewModel" />
</data>
<LinearLayout
android:id="@+id/ll_gallery_outer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.result}"
android:layout_gravity="center" />
<EditText
android:background="@color/cardview_shadow_end_color"
android:id="@+id/tv_account"
android:layout_width="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_height="40dp"
android:hint="输入用户名"
android:gravity="center"
android:text="@={viewModel.account}"
android:layout_gravity="center"
android:layout_marginTop="20dp" />
<EditText
android:background="@color/cardview_shadow_end_color"
android:id="@+id/tv_pwd"
android:layout_width="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_height="40dp"
android:hint="输入密码"
android:text="@={viewModel.pwd}"
android:gravity="center"
android:layout_gravity="center" />
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_height="50dp"
android:text="登录"
android:gravity="center"
android:layout_gravity="center" />
</LinearLayout>
</layout>
ViewModel代码
package com.cxj.mvvm_demo.vm;
import androidx.databinding.ObservableField;
import com.cxj.mvvm_demo.m.Model;
public class ViewModel extends androidx.lifecycle.ViewModel {
public ObservableField<String> account = new ObservableField<>("");
public ObservableField<String> pwd = new ObservableField<>("");
public ObservableField<String> result = new ObservableField<>("");
Model mModel;
public ViewModel() {
mModel = new Model();
}
public void login(){
boolean loginResult = mModel.login(account.get(), pwd.get());
result.set(loginResult ? "登录结果:成功" :"登录结果:失败");
}
}
在APP的bulid.gradle下添加配置
android{
....
buildFeatures{
dataBinding = true
}
}
运行结果
实现代码说明
通过Android提供的数据双向绑定库data binding 将Acitvity/xml视图层与ViewModel绑定。在xml布局文件中,通过@{ }来表示单向绑定或者@={ }来表示双向绑定。Activity接受到视图层的登录点击事件后,调用ViewModel处理登录业务逻辑,ViewModel通过双向数据绑定拿到到视图层输入的账号密码数据,调用Model处理数据,Model处理数据后,回传给ViewModel, ViewModel的数据改变,View感知后刷新页面。
注意:dataBinding通过观察者模式实现。
MVVM的优缺点
优点:经过数据双向绑定之后,我们不在需要想MVP中写那么多接口回调方法区实现视图层和业务层的交互。业务层也不再持有视图层的引用。
缺点:通过这种方式进行数据双向绑定后,xml中会多出一些标签、表达式、甚至和业务有点的简单计算代码。这不利于业务的逻辑的查看。并且由于双向绑定是dataBinding实现的。在这个过程中, 如果出现bug导致数据没有被感知改变,不方便排错,因为xml不能debug调试。
总结
MVC、MVP、MVVM大体上都是把系统划分成3个模块:视图层、业务层、数据层。 但是他们的通信方式、数据流动方向不一致,形成了不同的架构。 其后面产生的架构都是为了更好的解耦,解决已有架构的不足。每个架构都有自己的优缺点,没有最好的架构,只有最合适的架构。