如何构建Android MVVM运行程序
如何构建Android MVVM运行程序
Databinding 是一种框架,MVVM是一种形式,两者的概念是不一样的。我的了解DataBinding是一个成功数据和UI绑定的框架,只是一个成功MVVM形式的工具。ViewModel和View可以经过DataBinding来成功单向绑定和双向绑定,这套UI和数据之间的灵活监听和灵活降级的框架Google曾经帮咱们做好了。在MVVM形式中ViewModel和View是用绑定相关来成功的,所以有了DataBinding 使咱们构建Android MVVM 运行程序成为或许。1、概述
Databinding是一种框架,MVVM是一种形式,两者的概念是不一样的。我的了解DataBinding是一个成功数据和UI绑定的框架,只是一个成功MVVM形式的工具。ViewModel和View可以经过DataBinding来成功单向绑定和双向绑定,这套UI和数据之间的灵活监听和灵活降级的框架Google曾经帮咱们做好了。在MVVM形式中ViewModel和View是用绑定相关来成功的,所以有了DataBinding使咱们构建Android MVVM 运行程序成为或许。
之前看了很多关于DataBinding的博客和相关的一些Demo,大少数就是往xml规划文件传入一些数据,然后把这些数据绑定到控件上( 如TextViewbinding:text=“@{user.name} ),接着在这些控件上(如Buttonbinding:setOnClickListener=”@{user.listener}”)设置一些事情到控件上,基本讲述都是DataBinding的基本用法。但是并没有人通知你把一个onClickListener写到一个类并把这个listener绑定到xml外面上是不是不太好,也没有人通知你这个和xml规划绑定的ViewModel类应该放哪些数据,应该做什么事?应该如何设计?更是很少有博文来通知你在Android中如何经过Data Binding 去构建MVVM的运行框架。这也就是是本篇文章的重点。接上去,咱们先来看看什么是MVVM,然后在一步一步来设计整个运行程序框架。
源码地址
2、MVC、MVP、MVVM
首先,咱们先大抵了解Android开发中经常出现的形式,以便咱们更深化了解MVVM 形式。
View:对应于xml规划文件
Model:实体模型
Controllor:对应于Activity业务逻辑,数据处置和UI处置
从上方看起来各个组件的职责视乎还挺耦合MVC的,但是关上Android的一个Activity文件,一看一言难尽,Android中经常会产生数千行的Activity代码,究其要素,Android中纯正作为View的各个XML视图配置太弱,Activity基本上都是View和Controller的合体,既要担任视图的显示又要参与控制逻辑,承当的配置过多,代码量大也就无余为奇。一切更贴切的目前惯例的开发说应该是View-Model形式,大局部都是经过Activity的协调,衔接,和处置逻辑的。
View: 对应于Activity和xml,担任View的绘制以及与用户交互
Model: 依然是实体模型
Presenter: 担任成功View于Model间的交互和业务逻辑
在Android开发中MVP的设计思维用得比拟多,应用MVP的设计模型可以把局部的逻辑的代码从Fragment和Activity业务的逻辑移进去,在Presenter中持有View(Activity或许Fragment)的援用,然后在Presenter调用View暴露的接口对视图启动操作,这样无利于把视图操作和业务逻辑分开来。MVP能够让Activity成为真正的View而不是View和Control的合体,Activity只做UI相关的事。但是这个形式还是存在一些不好的中央,比拟如说:
复杂的业务同时会造成presenter层太大,代码臃肿的疑问。
View: 对应于Activity和xml,担任View的绘制以及与用户交互
Model: 实体模型
ViewModel: 担任成功View于Model间的交互,担任业务逻辑
MVVM的指标和思维MVP相似,应用数据绑定(Data Binding)、依赖属性(DependencyProperty)、命令(Command)、路由事情(Routed Event)等新个性,打造了一个愈加灵敏高效的架构。
在MVVM中,以前开发形式中必定先处置业务数据,然后依据的数据变动,去失掉UI的援用然后降级UI,经过也是经过UI来失掉用户输入,而在MVVM中,数据和业务逻辑处于一个独立的ViewModel中,ViewModel只需关注数据和业务逻辑,不须要和UI或许控件打交道。由数据智能去驱动UI去智能降级UI,UI的扭转又同时智能反应到数据,数据成为主导要素,这样使得在业务逻辑处置只需关心数据,繁难而且繁难很多。
MVVM形式中,数据是独立于UI的,ViewModel只担任处置和提供数据,UI想怎样处置数据都由UI自己选择,ViewModel不触及任何和UI相关的事也不持有UI控件的援用,即使控件扭转(TextView 换成 EditText)ViewModel简直不须要更改任何代码,专一自己的数据处置就可以了,假设是MVP遇到UI更改,就或许须要扭转失掉UI的形式,扭转降级UI的接口,扭转从UI上失掉输入的代码,或许还须要更改访问UI对象的属性代码等等。
在MVVM中,咱们可以在上班线程中间接修正ViewModel的数据(只需数据是线程安保的),剩下的数据绑定框架帮你搞定,很多事情都不须要你去关心。
MVVM的分工是十分显著的,由于View和ViewModel之间是松懈耦合的。一个是处置业务和数据,一个是专门的UI处置。齐全有两团体分工来做,一个做UI(xml 和Activity)一个写ViewModel,效率更高。
一个ViewModel复用到多个View中,雷同的一份数据,用不同的UI去做展现,关于版本迭代频繁的UI改动,只需改换View层就行,关于假构想在UI上的做AbTest更是繁难的多。
ViewModel外面是数据和业务逻辑,View中关注的是UI,这样的做测试是很繁难的,齐全没有彼此的依赖,不论是UI的单元测试还是业务逻辑的单元测试,都是低耦合的。
经过上方对MVVM的简述和其余两种形式的对比,咱们发现MVVM对比MVC和MVP来说还是存在比拟大的长处,只管目前Android开发中或许真正在经常使用MVVM的很少,但是是值得咱们去做一些讨论和调研。
3、如何构建MVVM运行程序
1). 如何分工
构建MVVM框架首先要详细了解各个模块的分工,接上去咱们来解说View,ViewModel,Model 的它们各自的职责所在。
View层做的就是和UI相关的上班,咱们只在XML和Activity或Fragment写View层的代码,View层不做和业务相关的事,也就是咱们的Activity不写和业务逻辑相关代码,也不写须要依据业务逻辑来降级UI的代码,由于降级UI经过Binding成功,降级UI在ViewModel外面做(降级绑定的数据源即可),Activity要做的事就是初始化一些控件(如控件的色彩,参与 RecyclerView的宰割线),Activity可以降级UI,但是降级的UI必定和业务逻辑和数据是没有相关的,只是单纯的依据点击或许滑动等事情降级UI(如依据滑动色彩突变、依据点击暗藏等单纯UI逻辑),Activity(View层)是可以处置UI事情,但是处置的只是处置UI自己的事情,View层只处置View层的事。繁难的说:View层不做任何业务逻辑、不触及操作数据、不处置数据、UI和数据严厉的分开。
ViewModel层做的事情刚好和View层雷同,ViewModel 只做和业务逻辑和业务数据相关的事,不做任何和UI、控件相关的事,ViewModel层不会持有任何控件的援用,更不会在ViewModel中经过UI控件的援用去做降级UI的事情。ViewModel就是专一于业务的逻辑处置,操作的也都是对数据启动操作,这些个数据源绑定在相应的控件上会智能去更改UI,开发者不须要关心降级UI的事情。DataBinding框架曾经允许双向绑定,这使得咱们在可以经过双向绑定失掉View层反应给ViewModel层的数据,并启动操作。关于对UI控件事情的处置,咱们也宿愿能把这些事情处置绑定到控件上,并把这些事情一致化,繁难ViewModel对事情的处置和代码的好看。为此咱们经过BindingAdapter对一些罕用的事情做了封装,把一个个事情封装成一个个Command,关于每个事情咱们用一个ReplyCommand<T>去处置就行了,ReplyCommand<T>会把或许你须要的数据带给你,这使得咱们处置事情的时刻也只关心处置数据就行了,详细见MVVMLight Toolkit 经常使用指南的 Command 局部。再强调一遍ViewModel 不做和UI相关的事。
Model 的职责很繁难,基本就是实体模型(Bean)同时包括Retrofit 的Service ,ViewModel 可以依据Model失掉一个Bean的Observable<Bean>( RxJava ),然后做一些数据转换操作和映射到ViewModel中的一些字段,最后把这些字段绑定到View层上。
2). 如何单干
关于单干,咱们先来看上方的一张图:
图 1
上图反响了MVVM框架中各个模块的咨询和数据流的走向,由上图可知View和Model 间接是解耦的,是没有间接咨询的,也就是我之前说到的View不做任何和业务逻辑和数据处置相关的事。咱们从每个模块逐一拆分来看。那么咱们重点就是上方的三个单干。
ViewModel与View的单干
图 2
图 2 中ViewModel 和View 是经过绑定的形式衔接在一同的,绑定的一种是数据绑定,一种是命令绑定。数据的绑定>
//一个变量蕴含了一切关于/***ViewStyle关于控件的一些属性和业务数据有关的Style可以做一个包裹,这样代码比拟好看,ViewModel页面也不会有太多的字段。**/
Context 是干嘛用的呢,为什么每个ViewModel都最好须要持了一个Context的援用呢?ViewModel不做和UI相关的事,不操作控件,也不降级UI,那为什么要有Context呢?要素关键有以下两点,当然也有其余用途,调用工具类、协助类或许须要context参数等:
经过图1中,咱们发现ViewModel 经过传参给Model然后失掉一个Observable<Bean>,其实这就是网络恳求局部,做网络恳求咱们必定把RetrofitService前往的Observable<Bean>绑定到Context的生命周期上,防止在恳求回来时Activity曾经销毁等意外,其实这个Context的目的就是把网络恳求绑定到页面的生命周期中。
在图1中,咱们可以看到两个ViewModel 之间的咨询是经过Messenger来做,这个Messenger是须要用到Context,这个咱们后续会解说。
Model 是什么呢,其实就是数据原型,也就是咱们用Json转上来的JavaBean,咱们或许都知道,ViewModel要把数据映射到View中或许须要少量对Model的数据拷贝,拿Model的字段去生成对应的ObservableField(咱们不会间接拿Model的数据去做展现),这里其实是有必要在一个ViewModel保管原始的Model援用,这关于咱们是十分有用的,由于或许用户的某些操作和输入须要咱们去扭转数据源,或许咱们须要把一个Bean从列表页点击后传给概略页,或许咱们须要把这个model 当做表单提交到主机。这些都须要咱们的ViewModel 持有相应的model。
Data Field (数据绑定)
Data Field 就是须要绑定到控件上的ObservableField字段,无可非议这是ViewModel的必定品。这个没有什么好说,但是这边有一个倡导:
这些字段是可以稍微做一下分类和包裹的,比如说或许一些字段绑定到控件的一些Style属性上(假设说:长度,色彩,大小)这些依据业务逻辑的变动而灵活去更改的,关于着一类针对ViewStyle的的字段可以申明一个ViewStyle类包裹起来,这样整个代码逻辑会更明晰一些,不然ViewModel外面或许字段众多,不易治理和浏览性较差。而关于其余一些字段,比如说title,imageUrl,name这些属于数据源类型的字段,这些字段也叫数据字段,是和业务逻辑毫不相关的,这些字段可以放在一块。
Command (命令绑定)
Command(命令绑定)说白了就是对事情的处置(下拉刷新,加载更多,点击,滑动等事情处置),咱们之前处置事情是拿到UI控件的援用,然后设置Listener,这些Listener其实就是Command,但是思考到在一个ViewModel 写各种Listener并不好看,或许成功一个Listener就须要成功多个方法,但是咱们或许只想要其中一个有用的方法成功就好了。同时成功Listener会拿到UI的援用,或许会去做一些和UI相关的事情,这和咱们之前说的ViewModel 不持有控件的援用,ViewModel不更改UI有相悖。更关键一点是成功一个Listener或许须要写一些UI逻辑能力最终失掉咱们想要的,繁难一点的比如说,你想要监听ListView滑到最底部然后触发加载更多的事情,这时刻你就要在ViewModel外面写一个OnScrollListener,然后在外面的onScroll方法中做计算,计算什么时刻ListView滑动底部了,其实ViewModel的上班并不想去处置这些事情,它专一做的应该是业务逻辑和数据处置,假设有一个物品它不须要你自己去计算能否滑究竟部,而是在滑动底部智能触发一个Command,同时把列表的总共的item数量前往给你,繁难你经过page=itemCount/LIMIT+1去计算出应该恳求主机哪一页的数据那该多好啊。MVVM Light Toolkit 帮你成功了这一点:
接着在XML 规划文件中经过bind:onLoadMoreCommand绑定上去就行了
详细想了解更多请检查 MVVM Light Toolkit经常使用指南,外面有比拟详细的解说Command的经常使用。当然Command并不是必定的,你齐全可以依照你的习气和喜好在ViewModel写Listener,不过经常使用Command 可以使你的ViewModel更繁复易读,你也可以自己定义更多的Command,自己定义其余配置Command,那么ViewModel的事情处置都是托管ReplyCommand<T>来处置,这样的代码看起来会特意好看和明晰。
Child ViewModel (子ViewModel)
子ViewModel 的概念就是在ViewModel外面嵌套其余的ViewModel,这种场景还是很经常出现的。比如说你一个Activity外面有两个Fragment,ViewModel是以业务划分的,两个Fragment做的业务不一样,人造是由两个ViewModel来处置,Activity 自身或许就有个ViewModel来做它自己的业务,这时刻Activity的这个ViewModel外面或许蕴含了两个Fragment区分的ViewModel。这就是嵌套的子ViewModel。还有另外一种就是关于AdapterView如ListView RecyclerView,ViewPager等。
它们的每个Item 其实就对应于一个ViewModel,然后在的ViewModel经过ObservableList<ItemViewModel>持有援用(如上述代码),这也是很经常出现的嵌套的子ViewModel。咱们其实还倡导,假设一个页面业务十分复杂,不要把一切逻辑都写在一个ViewModel,可以把页面做业务划分,把不同的业务放到不同的ViewModel,然后整合到一个总的ViewModel,这样做起来可以使咱们的代码业务明晰,冗长意赅,也繁难前人的保养。
总得来说ViewModel 和View之前仅仅只要绑定的相关,View层须要的属性和事情处置都是在xml外面绑定好了,ViewModel层不会去操作UI,只会操作数据,ViewModel只是依据业务要求处置数据,这些数据智能映射到View层控件的属性上。关于ViewModel类中蕴含哪些模块和字段,这个须要开发者自己去权衡,这边倡导ViewModel不要引入太多的成员变量,成员变量最好只要上方的提到的5种(context、model、…),能不进入其余类型的变量就尽量不要引出去,太多的成员变量关于整个代码结构破坏很大,前面保养的人要时辰关心成员变量什么时刻被初始化,什么时刻被清掉,什么时刻被赋值或许扭转,一个细节不小心或许就产生潜在的Bug。太多不明晰定义的成员变量又没有注释的代码是很难保养的。
ViewModel与Model的单干
从图1 中,Model 是经过Retrofit 去失掉网络数据的,前往的数据是一个Observable<Bean>( RxJava),Model 层其实做的就是这些。那么ViewModel做的就是经过传参数到Model层失掉到网络数据(数据库同理)然后把Model的局部数据映射到ViewModel的一些字段(ObservableField),并在ViewModel保管这个Model的援用,咱们来看下这一块的大抵代码(代码触及到繁难RxJava,如看疑问可以查阅入门一下):
//将网络恳求绑定到Activity的生命周期//变成Notification<Bean>使咱们更繁难处置数据和失误//给成员变量newsDetail赋值,之前提到的5种变量类型中的一种(model类型)//Model
以上代码基本把注释补全了,基本思绪比拟明晰,,Rxjava触及的操作符都是比拟基本的,如有疑问,可以稍微去入门,之后的源码外面ViewModel数据逻辑处置都是用Rxjava做,所以须要提早学习一下繁难你看懂源码。
注:咱们介绍经常使用MVVM 和RxJava一块经常使用,只管两者皆有观察者形式的概念,但是咱们RxJava不经常使用在针对View的监听,更多是业务数据流的转换和处置。DataBinding框架其实是公用于View-ViewModel的灵活绑定的,它使得咱们的ViewModel只须要关注数据,而RxJava提供的弱小数据流转换函数刚好可以用来处置ViewModel中的种种数据,失掉很好的用武之地,同时加上Lambda表白式联合的链式编程,使ViewModel的代码十分繁复同时易读易懂。
ViewModel与ViewModel的单干
在图 1 中 咱们看到两个ViewModel 之间用一条虚线衔接着,两边写着Messenger,Messenger可以了解是一个全局信息通道,引入messenger最关键的目的就成功ViewModel和ViewModel的通讯,也可以用做View和ViewModel的通讯,但是并不介绍这样做。ViewModel关键是用来处置业务和数据的,每个ViewModel都有相应的业务职责,但是在业务复杂的状况下,或许存在交叉业务,这时刻就须要ViewModel和ViewModel交流数据和通讯,这时刻一个全局的信息通道就很关键的。关于Messenger的详细经常使用方法可以参照 MVVM Light Toolkit 经常使用指南的 Messenger 局部,这边给出一个繁难的例子仅供参考:
场景是这样的,你的MainActivity对应一个MainViewModel,MainActivity外面除了自己的内容还蕴含一个Fragment,这个Fragment的业务处置对应于一个FragmentViewModel,FragmentViewModel恳求主机并失掉数据,刚好这个数据MainViewModel也须要用到,咱们无法能在MainViewModel从新恳求数据,这样不太正当,这时刻就须要把数据传给MainViewModel,那么应该怎样传,彼此没有援用或许回调。那么只能经过全局的信息通道Messenger。FragmentViewModel失掉信息后通知MainViewModel 并把数据传给它:
//上方的代码可以不看,就是失掉网络数据,经过send把数据传过去
在MainActivity onDestroy 敞开注册就行了(不然造成内存暴露)
当然上方的例子也只是繁难的说明下,Messenger可以用在很多场景,通知,广播都可以,不必定要传数据,在必定条件下也可以用在View层和ViewModel上的通讯和广播。运用范围特意广,须要开发者联合实践的业务中去做更深档次的开掘。
4、总结和源码
本篇博文解说关键是一些团体开发环节中总结的Android MVVM构建思维,更多是通常上各个模块如何分工,代码如何设计,只管如今业界经常使用AndroidMVVM形式开发还比拟少,但是随着DataBinding 1.0 的发布,置信在Android MVVM这块畛域会更多的人来尝试,刚好最近用MVVM开发了一段期间,有点心得,写进去仅供参考。
文中解说的环节代码比拟少,代码用到了自己开发的一个MVVM Light Toolkit 库,而且还是RxJava + Lambda的代码,预计很多人看着都晕菜了,这边会把源码发布进去。假设你还没有尝试过用RxJava+Retrofit+DataBinding 构建Android MVVM运行程序,那么你可以试着看一下这边的源码并且做一下尝试,说不定你会青睐上这样的开发框架。
关于MVVM Light Toolkit 只是一个工具库,关键目的是更快捷繁难的构建AndroidMVVM运行程序,在外面参与了一些控件额外属性和做了一些事情的封装,同时引进了全局信息通道Messenger,用起来确实十分繁难,你可以尝试一下,当然还有不少中央没有完善和提升,后续也会始终降级和提升,假设不能到达你的业务需求时,你也可以自己参与自己须要的属性和事情。假构想更深化了解MVVMLight Toolkit 请看我这篇博文 MVVM Light Toolkit 经常使用指南
源码地址
library —> library是MVVM Light Toolkit的源码,源码很繁难,感兴味的同窗可以看看,没什么多少的技术难度,可以依据自己的需求,参与更多的控件的属性和事情绑定。
sample —> 本文触及的代码均处出于这个名目,sample 一个知乎日报的App的繁难成功,代码蕴含了一大局部 MVVM LightToolkit的经常使用场景,(Data、Command、Messenger均有触及),同时sample严厉依照博文论述的MVVM的设计思维开发的,对了解本文有很大的协助,欢迎clone上去看看。
Sample 截图
源码触及 RxJava+Retrofit+Lambda 如有疑问或没接触过,花点期间入门一下,用到都是比拟繁难的物品。宿愿这篇博客在如何构建AndroidMVVM运行程序对你有所协助,如有任何疑问,可以给我留言,欢迎大家独特讨论,假设对MVVM Light Toolkit 有任何疑问,也可以反应给我。