一、简介
首先声明,本文讲解的Android DataBinding原理,不涉及Android DataBinding的配置和使用,如果大家想了解Android DataBinding的使用教程,请去Google Android官网,里面有非常详细的讲解。另外,本文也不是为Android DataBinding歌功颂德的,如果对着对本文的一些总结有不同观点,请留言,希望和大家一起思考这项“新技术”。
DataBinding框架是去年谷歌 I/O大会上介绍的“新技术”, 数据绑定框架能够给我们带来了一定的方便,无需findviewByID操作也可获取View,数据Model更新自动映射到控件上…… Android Databingding属于单向绑定框架。
顾名思义,DataBinding即数据绑定,数据绑定本不是什么新鲜技术,做asp.net Web开发的同学应该都用过Databinding绑定图表数据,C#本身也支持控件的数据绑定。在Android层面,Google也不是第一个做数据绑定的,开源项目RoboAndroid早已基于Android平台开发了一套数据绑定框架,RoboAndroid属于双向绑定框架。
单向绑定是指presentation model上的属性更新会自动的同步到相应的视图属性上。双向绑定在单向绑定的基础上,增加了将视图上的变更同步回presentation model相应的属性上。
二、为什么要有Databinding
这要从软件的视图逻辑架构模型说起,常见的模型有MVC、MVP和MVVM,这三种模型各有优缺点,看着很像,其实有较大不同,Android Databinding的作用就是将原来Android开发模式从MVC转到MVVM。Android的Activity+Layout文件模式属于MVC,我们做Android开发的时候会发现,一不小心一个Activity的代码就超过1千多行,视图逻辑和业务逻辑全部混在一起,代码的可维护性非常差,这是Google推出Databinding想解决的问题。
这里复制粘贴一下大牛们对这三个逻辑架构的理解。
1、MVC
MVC,顾名思义,MVC是将Model, View 和Controller分离,让彼此的职责(responsibility)能够明确的分开,这样不论是改M、 V还是C,都可以确保另外两层可不用做任何修改,同时这样的分层也可以加强程式的可测试性(testability),View和Model基本上是相关的,但它们并不会有直接的相依关系,而是由Controller去决定Model产生的资料,然后丢给View去做呈现,也就是说,Controller是Model和View之间的协调者(coordinator),View和Model不能直接沟通,以确保责任的分离。而Controller可以只是一个系结Model和View的小类别,也可以是大到包含Workflow, Enterprise Services或是做为外部系统的Proxy Services等的逻辑系统,MVC各元件是可以分离的组件,也可以是分离的系统(当然要设计一些机制在相互沟通)。可以看到MVC中Controller(Activity)中既要控制视图(Layout)也要处理业务(数据),Controller只是将View(layout)与Model尽可能分开,当然View也可以直接获取Model数据,如果将View与Model完全分开,就要使用MVP框架。
总结MVC:
1) 视图层(View):一般采用XML布局文件进行界面的描述,也可使用代码。
2) 控制层(Controller):Android的控制层是Activity或Fragment,一个Activity可以对应多个Fragment。目前点评Android的框架采用Fragment,大多数页面采用Fragment作为控制层。
3) 模型层(Model):数据模型,由于Android变量个数限制,目前点评Android几乎不存在Model。
缺点:
主要的缺点是Controller太复杂,显示逻辑和其他逻辑混合在一起不好维护;由于缺少数据模型支持,代码更混乱;模块、控件可复用性低。
2、MVP
MVP,MVP一样也是职责分明,且Model与View分离的架构,但是这个P (Presenter)和ViewModel就很类似,不过就如同Presenter (主持人)这个字所代表的意义,所有主控View呈现的工作,都是由Presenter来做,而View本身只是Presenter所要使用的舞台而已,所以View原则上会相依于Presenter,但是为了要做到关注点分离(SoC原则),所以在View和Presenter间都会加入一个介面(ex: IView),然后以IoC的方式将View注射到Presenter中,而Presenter就使用介面所定义的方法去操控,而View就透过介面所定义的方法去呈现介面即可。但也因为受限于介面,所以Presenter只能依介面定义的动作去回应与处理,而不能再做更多的延伸功能,除非更改View的介面。
3、MVVM
MVVM,MVVM的架构一样是M, V分离,但中间是以VM (ViewModel)来串接,这个ViewModel比较像是View的一个代理程式,它负责直接对Model做沟通,而View可以透过一些机制(ex: Events, Two-way Databindings, …)来和ViewModel沟通以取得资料或将资料抛给Model做存取等工作,ViewModel也可以作为和外部系统的代理程式,例如Web Service或是REST Service或是Enterprise Services等等,不过它和MVC不同的地方,就是ViewModel和View的黏合度比较高,因为View必须要透过ViewModel才可以取得Model,而ViewModel又必须要处理来自View的通知讯息,所以虽然职责一样分明,但是却不像MVC那样可以扩展到整个系统元件都能用。如果MVVM要和MVP比较的话,MVVM会比MVP更灵活一点。
总结MVVM:
1)低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的”View”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
2) 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
3) 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xaml代码。
4)可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。
由上面各个架构的讨论,我们可以得到以下的结果:
4、总结三种架构:
MVC 架构适合于大型系统,它可以分层且可以在实体层面切割为不同的机器或服务,只要彼此间具有适当的通讯协定即可。
MVVM 架构适合像XAML 这种与程式码无关(code ignorance) 的使用者介面设计,只要View 中下特定的指令与ViewModel 串接,就可以享有ViewModel 沟通的功能,而ViewModel 只需做一些特别的介面实作,即可平顺的和View 沟通。
MVP 架构适合集中由程式码决定View 动作的应用程式,而View 只需要实作特定的介面即可,不需要太复杂的工作,但Presenter 则可能会受限于View 介面的动作,而无法做更进一步对View 的控制。
5、小结
在Android开发中原有的MVC(Activity+layout)模式越来越不适用,首先,视图逻辑和业务逻辑不分,导致代码容易出问题、难以可持续性维护;其次,由于业务逻辑混在视图逻辑里面,视图基本无法复用,layout本身是代码文件,但是又不像java代码那样可维护,灵活,可以有逻辑,所以很少复用layout文件,有经验的Android程序员会尽可能避免复用Layout文件特别是复用别人写的layout文件。所以出于视图复用的目的原有的MVC也不适用,MVVM成了一种必要的选择。
6、强调
本文需要说明的是Android Databinding只是在Android平台实现MVVM的一种方式,前面说的RoboAndroid也可以实现;或者开发者自己定义一套开发规范和框架,能够将Android开发大道视图、逻辑业务分离,并实现视图高度可复用也是一样的;RxJava也为开发者提供了MVVM的能力。
(1)RoboBinding?
RoboBinding是一款基于Android的数据绑定组件,支持双向绑定等,比较成熟,和DataBinding 类似,因为DataBinding借鉴了RoboBinding,目前DataBinding只支持单向绑定。
与DataBinding相比较, RoboBinding更为成熟,并且支持双向绑定,但是因为DataBinding是Google亲儿子,以后肯定会不断改进,会成为Android新特性,所以采用DataBinding可能更现实,但是我本人并不排斥RoboBinding,通过体验RoboBinding也很不错,侵入性并不是很强
(2)RxJava/ RxAndroid ?
RxJava最核心的两个东西是Observables(被观察者,事件源)和Subscribers(观察者)。Observables发出一系列事件,Subscribers处理这些事件。这里的事件可以是任何你感兴趣的东西(触摸事件,web接口调用返回的数据…);一个Observable可以发出零个或者多个事件,知道结束或者出错。每发出一个事件,就会调用它的Subscriber的onNext方法,最后调用Subscriber.onNext()或者Subscriber.onError()结束。
RxJava更为灵活,但是观察、订阅需要在代码中自己实现,侵入性比较强,也影响代码可读性,就目前代码来看,改造起来代价非常大。在Android项目中很少使用RxJava,虽然功能很强大,将逻辑看做数据流,一切数据驱动,但是代码侵入性太强,不适合在业务逻辑、视图逻辑中大范围使用。但是,RxJava在数据流控制中确实精妙!可以将RxJava包装到你的框架中,负责同一个Activity模块间的数据流控制,用他实现数据数据共享、消息通信,以数据驱动,将其封装到框架中,会是很好的选择。
三、Android DataBinding分析
View —— Layout文件:
手动在Layout文件中使用Model数据为控件赋值。
ViewModel —— ViewDataBinding 实现类
DataBinding框架会根据Layout进行的数据绑定情况自动生成该文件!不可改。 ViewDataBinding负责将Model的数据和更新信息赋值给Layout中的控件,达到单向绑定效果。
Model —— 实现Observable、 ObservableMap或ObservableList接口
负责数据逻辑处理,按照规定的标准写get、set方法,并通知数据更新。框架会在Model内部存储ViewDataBinding ,当Model需要更新数据时,可以通知ViewDataBinding 实现对View更新。
1、例子代码
(1)Model
public class OrderListItemModel extends BaseObservable{ //model继承BaseObservable类
private boolean checked; //定义属性
private int checkBoxVisibility; //定义属性
@Bindable //注解,支持自动更新
public boolean getChecked() {
return checked;
}
@Bindable
public void setChecked(boolean checked) {
this.checked = checked;
//通知OrderListItemModel 中的ViewDataBinding,更新checked属性
notifyPropertyChanged(BR.checked);
}
(2)Layout(View)
声明变量
<layout
xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:dp=“http://schemas.android.com/apk/res-auto”
>
<data>
<variable
name=“itemMode”
type=“com.dianping.tuan.ViewModel.OrderListItemModel”>
</variable>
</data>
绑定数据
<CheckBox
android:id=“@+id/check”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_gravity=“center_vertical”
android:button=“@drawable/rad_bg”
android:checked=“@{itemMode.checked}” //绑定checked
android:visibility="@{itemMode.checkBoxVisibility}“ //绑定Visibility
android:clickable="false"
android:paddingRight="10dp" />
(3)ViewModel (桥梁)—— ViewDataBinding
ViewDataBinding文件是框架根据layout文件和model自动生成的,无法修改。TuanOrderCommonItem2Binding类就是框架自动生成的ViewModel,父类是ViewDataBinding(抽象类),是在ViewDataBinding类中完成绑定。
public class TuanOrderCommonItem2Binding extends android.databinding.ViewDataBinding {
this.check = (android.widget.CheckBox) bindings[1];//存储Layout中的控件
private com.dianping.tuan.Model.OrderListItemModel mItemMode; //存储Model数据
// read checked~.~ itemMode ~
if ( itemMode != null)
{
checkedItemMode = itemMode.isChecked(); //获取ItemMode中的数据
}
if ((dirtyFlags & 0b11L) != 0)
{
this.check.setChecked(checkedItemViewMode); //将数据赋值给控件
}
……………………
2、Model如何通知ViewDataBinding更新View?
框架通过观察者模式,异步更新界面!我们看到过程非常复杂,最关键,数据更新的过程是异步的,这可以避免ANR,但是效率呢?如果是数据量比较大的列表或者比较重的主界面,使用数据绑定合适吗?
四、Android Databing总结
本文不是来为Android Databing歌功颂德的,如何使用一项新技术需要智慧,在我们未完全了解它时,最好谨慎的在工程项目中使用。最后罗列一些自己对Android Databing的总结,其中可能有不完善或不成熟的地方,希望大牛们批评指正。如果读者想在自己开发的APP中使用Android Databing,希望你对它优缺点有足够的了解,有充足的思想准备。
优点:
1、自动化绑定+MVVM优点
2、使用DataBinding后,无需直接获取、操作视图元素,能够帮助 Activity或Fragment减少对视图控制的代码量
不足:
1、目前只支持单向绑定;
2、ViewModel与View一一对应;
3、使用起来灵活性比较低;
4、Model属性发生变化时,ViewDatabinding采用异步更新数据,对于现实大量数据的ListView,会有一定延迟,在实践测试中发现,Databing效率较低,对于负责的界面不太适用;
5、自动生成大量代码和属性字段:ViewDataBinding 实现类 DataBinderMapper 等
参考文献
1、Google Android DataBinding:
http://developer.android.com/intl/zh-cn/tools/data-binding/guide.html
2、MVC、MVVM、MVP讲解:
http://www.cnblogs.com/xxdotnet/archive/2012/03/30/2425539.html
3、百度百科:MVP模式
http://baike.baidu.com/view/3456444.htm
4、Robobinding参考:
http://robobinding.github.io/RoboBinding/getting_started.zh.html
5、Android中的Data Binding初探:
https://www.aswifter.com/2015/07/04/android-data-binding-1/