Android 中的mvvm,Androidmvvm
摘要:我们来了解一下MVVM模式与Databinding ,MVVM是一种模式,Databinding 是一种框架。DataBinding是一个实现数据和UI绑定的框架。而ViewModel和View可以通过DataBinding来实现单向绑定和双向绑定,这套UI和数据之间的动态监听和动态更新的框架Google已经帮我们做好了。MVVM的思想和MVP类似。在MVVM模式中ViewModel和View是用绑定关系来实现的。
首先我们看一下mvvm中view、model、viewmodel三者是如何分工:
View: 简单地说不做任何业务逻辑、不涉及处理数据、操作数据,把UI和数据分离。
Model: 实体模型,同时包括Retrofit 的Service ,ViewModel 可以根据Model 获取一个Bean的Observable<Bean>( RxJava ),然后 做一些数据转换操作和映射到ViewModel 中的一些字段,最后把这些字段绑定到View层上。
ViewModel: 负责完成View于Model间的交互,负责业务逻辑。ViewModel层做的事情刚好和View层相反,ViewModel 只做和业务逻辑和 业务数据相关的事,不做任何和UI、控件相关的事,ViewModel 层不会持有任何控件的引用,更不会在ViewModel中通过UI 控件的引用去做更新UI的事情。ViewModel就是专注于业务的逻辑处理,操作的也都是对数据进行操作,这些个数据源绑定 在相应的控件上会自动去更改UI。记住:viewModel不做和UI相关的事。
我们在看看它的优势:
-
低耦合度:在MVVM模式中,数据是独立于UI的,而ViewModel只负责处理和提供数据,UI想怎么处理数据都是由UI自己决定的,ViewModel 不涉及任何和UI相关的事也不持有UI控件的引用,即使控件改变,ViewModel 几乎不需要更改任何代码。
-
更新UI:在MVVM中,我们可以在工作线程中直接修改View Model的数据(只要数据是线程安全的),剩下的就不需要你去关心,数据绑定框架会帮我们搞定。
-
可复用性:一个View Model复用到多个View中,同样的一份数据,用不同的UI去做展示,对于版本迭代频繁的UI改动,只需更换View层就行,对于如果想在UI上的做AbTest 更是方便的多。
- 单元测试:View Model里面是数据和业务逻辑,View中关注的是UI,这样做测试是很方便的,完全没有彼此的依赖,不管是UI的单元测试还是业务逻辑的单元测试,都是低耦合的。
view与viewmodel的协作:
Model 是通过Retrofit 去获取网络数据的,返回的数据是一个Observable<Bean>( RxJava ),Model 层其实做的就是这些。那么ViewModel 做的就是通过传参数到Model层获取到网络数据(数据库同理)然后把Model的部分数据映射到ViewModel的一些字段(ObservableField),并在ViewModel 保留这个Model的引用。
三者的关系:
看完上面的图,相信大家有了了解,接下来我们看看在代码中的实现:
首先在项目里添加依赖:
classpath 'com.android.tools.build:gradle:1.2.3'
classpath 'com.android.databinding:dataBinder:1.0-rc0'
这里用到 Data Binding,所以在Data Binding的模块添加插件,在build里添加。
apply plugin: 'com.android.databinding'
接下来我们看一下它的布局文件:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="viewModel" type="cn.saiz.mvvmhello.MainViewModel"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="10dp"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:textSize="16sp" android:textColor="@android:color/black" android:gravity="center" android:text="用户名:"/> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="simon" android:text="@={viewModel.userName}" app:addTextChangedListener="@{viewModel.userNameEditTextWatcher}"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="10dp"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:textSize="16sp" android:textColor="@android:color/black" android:gravity="center" android:text="密码:"/> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="123456" android:text="@={viewModel.passWord}" app:addTextChangedListener="@{viewModel.passwordEditTextWatcher}"/> </LinearLayout> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="@{viewModel.login}" android:text="登录"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="注册"/> </LinearLayout> </layout>
相信大家看到了,我们的根节点变成了layou