开发模式——MVVM框架开发

2019-04-13 22:16发布

这里写图片描述
MVVM是Model-View-ViewModel的简写。微软的WPF带来了新的技术体验,如Silverlight、音频、视频、3D、动画……,这导致了软件UI层更加细节化、可定制化。同时,在技术层面,WPF也带来了 诸如Binding、Dependency Property、Routed Events、Command、DataTemplate、ControlTemplate等新特性。MVVM(Model-View-ViewModel)框架的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。它立足于原有MVP框架并且把WPF的新特性糅合进去,以应对客户日益复杂的需求变化。 这种模式的引入就是使用ViewModel来降低View和Model的耦合,说是降低View和Model的耦合。也可以说是是降低界面和逻辑的耦合,理想情况下界面和逻辑是完全分离的,单方面更改界面时不需要对逻辑代码改动,同样的逻辑代码更改时也不需要更改界面。同一个ViewModel可以使用完全不用的View进行展示,同一个View也可以使用不同的ViewModel以提供不同的操作。 这种模式跟经典的MVP(Model-View-Presenter)模式很相似,除了你需要一个为View量身定制的model,这个model就是ViewModel。ViewModel包含所有由UI特定的接口和属性,并由一个 ViewModel 的视图的绑定属性,并可获得二者之间的松散耦合,所以需要在ViewModel 直接更新视图中编写相应代码。数据绑定系统还支持提供了标准化的方式传输到视图的验证错误的输入的验证。 MVVM优点编辑
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点
1. 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的”View”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
2. 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
3. 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xml代码。
4. 可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。 1.Model Model就是一个class,是对现实中事物的抽象,开发过程中涉及到的事物都可以抽象为Model,例如客户,客户的姓名、编号、电话、住址等属性也对应了class中的Property,客户的下订单、付款等行为对应了class中的方法。
  1. View
View很好理解,就是界面。
  1. ViewModel
上面说过Model抽象,那么ViewModel就是对View的抽象。显示的数据对应着ViewMode中的Property,执行的命令对应着ViewModel中的Command。 如果说MVP是对MVC的进一步改进,那么MVVM则是思想的完全变革。它是将“数据模型数据双向绑定”的思想作为核心,因此在View和Model之间没有联系,通过ViewModel进行交互,而且Model和ViewModel之间的交互是双向的,因此视图的数据的变化会同时修改数据源,而数据源数据的变化也会立即反应到View上。
这里写图片描述
1.基本使用
创建好一个Android Project之后,在gradle文件中添加如下几行代码,表示开启databinding: android { ... ... ... dataBinding{ enabled true } } 就是这么简单,一个简单的databinding配置之后,就可以开始使用数据绑定了。
要使用数据绑定,我们得首先创建一个实体类,比如User实体类,如下: public class UserEntity { private String username; private String nickname; private int age; public UserEntity() { } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public UserEntity(int age, String nickname, String username) { this.age = age; this.nickname = nickname; this.username = username; } } 然后我们来看看布局文件该怎么写,首先布局文件不再是以传统的某一个容器作为根节点,而是使用作为根节点,在节点中我们可以通过节点来引入我们要使用的数据源,如下: <layout xmlns:android="http://schemas.android.com/apk/res/android" > <data> <variable name="user" type="org.lenve.databinding1.UserEntity"/> data> <LinearLayout xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="org.lenve.databinding1.MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.username}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.nickname}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{String.valueOf(user.age)}"/> LinearLayout> layout> 在data中定义的variable节点,name属性表示变量的名称,type表示这个变量的类型,实例就是我们实体类的位置,当然,这里你也可以换一种写法,如下: <data> <import type="org.lenve.databinding1.UserEntity"/> <variable name="user" type="UserEntity"/> </data> 先使用import节点将UserEntity导入,然后直接使用即可。但是如果这样的话又会有另外一个问题,假如我有两个类都是UserEntity,这两个UserEntity分属于不同的包中,又该如何?看下面: <data> <import type="org.lenve.databinding1.UserEntity" alias="Lenve"/> <variable name="user" type="Lenve"/> </data> 在import节点中还有一个属性叫做alias,这个属性表示我可以给该类取一个别名,我给UserEntity这个实体类取一个别名叫做Lenve,这样我就可以在variable节点中直接写Lenve了。
看完data节点我们再来看看布局文件,TextView的text属性被我直接设置为了@{user.username},这样,该TextView一会直接将UserEntity实体类的username属性的值显示出来,对于显示age的TextView,我用了String.valueOf来显示,因为大家知道TextView并不能直接显示int型数据,所以需要一个简单的转换,事实上,我们还可以在{}里边进行一些简单的运算,这些我一会再说。
最后,我们来看看Activity中该怎么写,setContentView方法不能够再像以前那样来写了,换成下面的方式: DataBindingUtil.setContentView(this, R.layout.activity_main) 该方法有一个返回值,这个返回值就是系统根据我们的activity_main.xml布局生成的一个ViewModel类,所以完整写法如下:
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
有了ViewModel,再把数据绑定上去就可以了,如下: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); UserEntity user = new UserEntity(); user.setAge(34); user.setUsername("zhangsan"); user.setNickname("张三"); activityMainBinding.setUser(user); }