前言

本文俩个任务:

* 1.对MVVM进行学习
* 2.总结梳理MVC-MVP-MVVM的演进过程
什么是MVVM


MVP是对MVC的C的演化,MVVM是对MVP的P的演化。而Android领域的MVVM自身也进行了一次演化,即从2015年DataBinding推出开始,由传统的MVVM到2017谷歌推出了AAC标准架构。并在二者迭代的过程中,也出现了基于传统的DataBinding增强的方案(
MVVM Light Toolkit使用指南 <https://www.jianshu.com/p/43ea7a531700>)。


MVVM是一种思想。即UI随数据更改而更改。它独特的地方就在于它的DataBinding特性。但请注意,虽然Google2015专门发布了一个库叫做DataBinding,但是这里说的DataBinding并不是指的某个具体的库,而是指的一种
“行为”,指的是一类的”将数据Model映射到View”的框架。譬如老的DataBing库,新AAC的LiveData。

View: 对应于Activity和XML,负责View的绘制以及与用户交互。
Model: 实体模型。
ViewModel: 负责完成View与Model间的交互,负责业务逻辑。

特点

数据驱动


在常规的开发模式中,数据变化需要更新UI的时候,需要先获取UI控件的引用,然后再更新UI。获取用户的输入和操作也需要通过UI控件的引用。在MVVM中,这些都是通过数据驱动来自动完成的,数据变化后会自动更新UI,UI的改变也能自动反馈到数据层,数据成为主导因素。这样MVVM层在业务逻辑处理中只要关心数据,不需要直接和UI打交道,在业务处理过程中简单方便很多。

低耦合度

MVVM模式中,数据是独立于UI的。


数据和业务逻辑处于一个独立的ViewModel中,ViewModel只需要关注数据和业务逻辑,不需要和UI或者控件打交道。UI想怎么处理数据都由UI自己决定,ViewModel不涉及任何和UI相关的事,也不持有UI控件的引用。即便是控件改变了(比如:TextView换成EditText),ViewModel也几乎不需要更改任何代码。它非常完美的解耦了View层和ViewModel,解决了上面我们所说的MVP的痛点。

更新UI


在MVVM中,数据发生变化后,我们在工作线程直接修改(在数据是线程安全的情况下)ViewModel的数据即可,不用再考虑要切到主线程更新UI了,这些事情相关框架都帮我们做了。

团队协作


MVVM的分工是非常明显的,由于View和ViewModel之间是松散耦合的:一个是处理业务和数据、一个是专门的UI处理。所以,完全由两个人分工来做,一个做UI(XML和Activity)一个写ViewModel,效率更高。

可复用性


一个ViewModel可以复用到多个View中。同样的一份数据,可以提供给不同的UI去做展示。对于版本迭代中频繁的UI改动,更新或新增一套View即可。如果想在UI上做A/B
Testing,那MVVM是你不二选择。

单元测试


有些同学一看到单元测试,可能脑袋都大。是啊,写成一团浆糊的代码怎么可能做单元测试?如果你们以代码太烂无法写单元测试而逃避,那可真是不好的消息了。这时候,你需要MVVM来拯救。


我们前面说过了,ViewModel层做的事是数据处理和业务逻辑,View层中关注的是UI,两者完全没有依赖。不管是UI的单元测试还是业务逻辑的单元测试,都是低耦合的。在MVVM中数据是直接绑定到UI控件上的(部分数据是可以直接反映出UI上的内容),那么我们就可以直接通过修改绑定的数据源来间接做一些Android
UI上的测试。

MVVM的俩种方案

传统方式:DataBinding库

在学习MVVM架构思想之前,首先需要明白dataBinding这个工具如何使用
<https://blog.csdn.net/user11223344abc/article/details/82627791>。


在懂了如何使用dataBinding的情况下,再来思考架构模式,我的思路是,这个架构既然是由MVP演化而来,那么我们完全可以按照设计Poresenter的方法来设计ViewModel,ok,这是第一步,然后第二步,我们presenter里边持有了View和Model的引用,并根据业务逻辑对二者进行组织,那么,我们的ViewModel也根据这种思路来写,既然是已数据为驱动,编写设计这个架构代码的切入点肯定还是从Model.loadData()进行切入。在拿到数据之后,我们不再需要像VC或VP那样要考虑”这个数据该放在哪个View控件上”这类问题。

M:数据Bean或IModel,和MVP一样
V:Activity和xml布局

VM:Presenter的进化,只是数据会利用dataBinding框架的双向绑定特性对数据进行绑定,最直观的结果就是我们设置数据不再是拿到某个具体的View,而是利用框架生成的Binding文件setXXX(Bean),譬如ActivityMainBinding.setUser(user)

优势总结:

* View和Model双向绑定,一方的改变都会影响另一方,开发者不用再去手动修改UI的数据。二者互相自动。
*
不需要findViewById也不需要butterknife,不需要拿到具体的View去设置数据绑定监听器等等,这些都可以用DataBinding完成。是不是很舒服?
* View和Model的双向绑定是支持生命周期检测的,不会担心页面销毁了还有回调发生,这个由lifeCycle完成。
* 不会像MVC一样导致Activity中代码量巨大,也不会像MVP一样出现大量的View和Presenter接口。项目结构更加低耦合。
2017新方案,AAC(LiveData)

AAC入门我之前写过一篇文章,要看的同学戳这里
<https://blog.csdn.net/user11223344abc/article/details/79364274>

到了这一步,侧重点在于与传统DataBinding框架的纵向对比,而非与MVP,MVC的横向对比。

还是简要说说AAC的特点:

它有个几个成员:LifeCycle,LiveData,Room,ViewModel。其中前三个都是为ViewModel服务的辅助。抛开Room不谈(数据存储),LiveData和LifeCycle都是和LifecycleRegistryOwner,LifecycleObserver相关的,它们包含声明周期与观察者模式俩层含义。使用观察者模式是为了让数据绑定成为可能,它提供了事件传递的属性。

一般来说,我们封装一个MVVM By AAC的架构遵循以下套路:

* Model
DataBean extends LiveData impl LifecycleObserver,让Model具备被传递的可能以及和生命周期绑定

* View
是Activity,通过liveData的observe接收ViewModel传过来的事件传递
final MutableLiveData<List<UserLiveData>> users = model.getUsers();
MainActivity extends AppCompatActivity implements LifecycleRegistryOwner {
users.observe(this, new Observer<List<UserLiveData>>() { @Override public void
onChanged(@Nullable List<UserLiveData> userLiveData) { Log.e("MainActivity",
"更新UI"); } }); }
* ViewModel
负责加载数据,逻辑编写,以及将Model以观察者事件形式传递给View
public class UserViewModel extends ViewModel{ private
MutableLiveData<List<UserLiveData>> users;public
MutableLiveData<List<UserLiveData>>getUsers() { if(null == users){ users = new
MutableLiveData(); } loadUsers();return users; } private void loadUsers() { //
setValue } }
* 当然,在API26之后我们完全不需要这么复杂,因为它已经将这一套封装到support包内了。

以下例子是纯框架的使用,并没有进行MVVM的封装,只是为了展示,即使我不继承LiveData这些乱七八糟的类就能在API26+上实现这个功能,可以把这个例子当做练习,改造一下。
package proxy.zj.com.networklivedata.bean; /** * Created by thinkpad on
2018/2/27. */ public class TestData { String content = ""; public TestData
(String content) {this.content = content; } public String getContent() { return
content; }public void setContent(String content) { this.content = content; } }
public class OkGoActivity extends AppCompatActivity { private TextView content;
@Override protected void onCreate(Bundle savedInstanceState) { super
.onCreate(savedInstanceState); setContentView(R.layout.activity_ok_go); content
= findViewById(R.id.content);
//"https://api.douban.com/v2/movie/top250?start=0&count=10" OkGo.init(this
.getApplication());
//***************************************获取数据********************************************
final OkGoViewModel model = ViewModelProviders.of(this
).get(OkGoViewModel.class); findViewById(R.id.getdata).setOnClickListener(new
View.OnClickListener() {@Override public void onClick(View view) {
MutableLiveData data = model.getData(); data.observe(OkGoActivity.this, new
Observer<TestData>() {@Override public void onChanged(@Nullable TestData o) {
content.setText(o.getContent()); } }); } });
//*******************************************************************************************
} }
总结(MVC->MVP->MVVM)

MVC

M:数据Bean和IModel,数据请求一般写在IModel(impl)
V:xml布局文件
C:Activity,直接持有Model引用,在Activity内直接请求数据,然后再绘制UI



MVP

Moudel:
Model还是保持MVC的特性,数据Bean和IModel,数据请求一般写在IModel(impl)

View:

Activity,XML,相比MVC,不单单的再将xml布局文件视为View,Activity也不再作为一个Controller而是作为View的一部分而存在,这也是解耦的一个体现,也符合了Android设计Activity这个组件的初衷。

Presenter:
由Controller进化而来,持有View和Modle的引用,根据业务逻辑将二者进行梳理放置



另外关于MVP的代码实践我总结了一张脑图,大分辨率的,点击下载
<https://download.csdn.net/download/user11223344abc/10659580>

MVVM



mvvm对mvp的横向演进,用(单/双向)绑定机制解放了我们拿到数据关注某个具体控件,并隐式的绑定了View层的生命周期,在内存泄漏上有一定优势。
mvvm对自身的纵向演进,由谷歌2015原生的dataBinding框架到谷歌2017 AAC标准框架(LiveData LifeCycle
ViewModel) 。

Thanks

https://www.jianshu.com/p/a898ef83f38c <https://www.jianshu.com/p/a898ef83f38c>
https://www.jianshu.com/p/53925ccb900e <https://www.jianshu.com/p/53925ccb900e>
https://www.jianshu.com/p/c0988e7f31fd <https://www.jianshu.com/p/c0988e7f31fd>
//Android官方MVVM框架实现组件化之整体结构(强烈推荐)

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信