随着移动应用前端化越来越严重,原生应用开发的比重逐渐降低,慢慢被微信小程序/ReactNative/Weex/H5+/混合应用等替代,而这些前端化的技术栈中,mvvm模式最受推崇。
google在2015年的I/O大会就推出了mvvm模式的DataBinding框架,而在实际项目中被使用的情况并不多,在前端技术快速发展的今天,mvvm模式被推向了风口浪尖,而Android的DataBinding又一次受到了关注。
在google的2017年I/O大会上,kotlin被指定为Android开发官方语言,本篇以一个小例子记录DataBinding在kotlin环境下的配置以及使用,以及和前端框架Vue的mvvm模式的比较。
建议以了解MVVM模式为前提阅读本篇
添加工程依赖
新建一个新的基于kotlin的Android工程后,需要在gradle的配置文件中增加一些配置和依赖才能使用DataBinding。
在项目的build.gradle文件中,先把plugin的版本号抽出来,作为一个全局变量,便于配置使用
buildscript {
ext.kotlin_version = '1.1.51'
ext.android_plugin_version = '3.0.1' //把plugin版本号定义一个变量
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:$android_plugin_version" //使用变量代替原版本号
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
...
在app的build.gradle文件中增加配置
...
android {
...
dataBinding {
enabled = true
}
}
dependencies {
...
kapt "com.android.databinding:compiler:$android_plugin_version"
}
kapt {
generateStubs = true
}
配置完成后,这个Android工程已经支持DataBinding服务器托管网框架了。
XMl文件处理
为了演示方便,先调整下初始工程的MainActivity对应的布局文件activity_main.xml的内容
这是一个非常简单的布局,包含一个TextView和一个EditText,下面以编辑EditText的内容同步更改TextView的内容为目的来使用DataBinding对xml进行改造。
调整到的地方有:
- 布局文件的根标签改为了
...
, - 增加了
...
来声明DataModel变量 - 使用
@{...}
语法替换布局中原有常量 - 使用
android:addTextChangedListener="@{user.nameWatcher}"
进行EditText数据的双向绑定
在...
声明了一个叫做user的变量,并指定了user的类的定义,这里的user只是声明变量,并没有实例化,变量的实例化过程并不是在xml文件中,而是在绑定xml文件的代码中进行的。
定义ViewModel类
正常情况下,定义一个kotlin类是如下格式
class User {
var name: String? = null
}
在本次的DataBinding场景中,需要改造进行一些改造
class User {
var name = ObservableField()
val nameWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable) {
if (s.toString() != name.get()) {
name.set(s.toString())
}
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
}
}
这个类变得复杂了很多,name的类型改为了名为ObservableField的包装类,通过name.get和name.set方法来对name的值进行修改,达到监听的目的。
增加了名为nameWatcher的监听对象,在监听回调中,判断值的变更并对name变量进行赋值。
调整Activity
在常规模式中,我们使用setContentView(R.layout.activity_main)
来指定Activity的布局文件,而使用DataBinding时,我们要使用下面的代码来替换:
val activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
activityMainBinding.user = User()
DataBinding框架根据activity_main.xml文件自动生成了名为ActivityMainBinding的绑定类,通过根据布局文件实例化的绑定类,可以给DataModel变量user进行实例化。
小结
经过上述的调整,这个小功能形成了一个完整的闭环:
- Activity中根据布局文件创建布局View,并通过Binding给xml中的user变量赋值
- 布局中通过
android:text="@{user.name, default=默认值}"
语法监听并更新text - 布局中通过
android:addTextChangedListener="@{user.nameWatcher}"
监听EditText组件的内容变更,并更新user对象的name属性,name属性变更后会通知所有使用@{user服务器托管网.name}语法的控件进行更新
这是一个非常简单的DataBinding示例,更高级的特性不会在这里展示。
为什么呢?因为笔者并不会在实际项目中使用它,那么为什么呢?通过如两个对比来说明原因。
与Kotlin+anko对比
在app的build.gradle文件中增加anko的依赖
implementation "org.jetbrains.anko:anko:0.10.5"
xml文件保持常规写法不变
user类文件保持常规写法不变
Activity保持常规写法不变
要实现这个效果,只需要在Activity中加入5行代码
et_demo1.textChangedListener {
onTextChanged { charSequence, _, _, _ ->
tv_demo1.text = charSequence
}
}
于Vue对比
或许拿Android的框架和前端框架对比并不怎么合适,但同样是MVVM模式,我或许更喜欢Vue一些?
{{name}}
export default {
data: function () {
return {
name: '默认值'
};
}
};
嗯 清爽!
总结
DataBinding的诞生或许只是为了MVVM而MVVM,也或许DataBinding是在2015年设计的所以并没有Vue这种清爽的形式。
这个示例只是实现一个简单的功能,DataBinding更高级的特性并没在这里展示,DataBinding对代码的入侵性太强,常规开发中从网络获取数据是直接反序列化为实体类并进行展示的,而DataBinding则不能正常反序列化,还需要手动转换。
总之笔者认为在项目中引入DataBinding的弊大于利,在越来越多开发者从Java阵营转入kotlin阵营的形势下,DataBinding显得较为臃肿。
在日常开发中或许kotlin+anko和ReactNative比DataBinding更加方便。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net