文章目录
- 第一部分:DataBinding入门
- 配置项
- Layout标签使用
- 数据绑定
- 第一种绑定方法
- 第二种常规方式
了解DataBinding的使用,请参考:
如果你暂时无法翻墙,看这篇文章也可以。
本文中,默认的View就是Activity及其对应的XML文件。
第一部分:DataBinding入门
配置项
在Android中,需要使用DataBinding来支持MVVM的双向绑定。
在Android中的DataBinding需要在module下的build.gradle中申明:
android {
// ......
dataBinding{
enabled = true
}
// ......
}
Layout标签使用
想让DataBinding
生效,还需要在View
对应的XML中间中使用layout
标签,它就像个命名空间一样。类似于:
<?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"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
在这个layout
标签包裹的命名空间下,有一个data
标签,你可以通过该标签,在View
的XML文件中引入Model
的变量,这个留在后面说。
我们前面说了在MVVM中,Activity
和对应的XML文件共同组成了View
,那么它们是怎么联系到一起得呢?
一般来说,XML文件,通过Activity的setContentView函数,将XML文件,交给Activity控制。就像这样:
setContentView(R.layout.activity_main);
那么,在DataBinding框架下,我们得换个新得姿势:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
}
setContentView
的函数名相同,但调用实例却从传统的Activity换成了DataBindingUtil
的静态函数。
聪明的小伙伴已经注意到了,为啥莫名其妙多了个ActivityMainBinding类?这不是我干的!!!!解释一下。
当你在XML文件中正确的添加了<layout></layout>
标签时,AndroidStudio会通过DataBinding框架,自动生成了一个类,这个类的包名遵循如下规则:
规则一:项目包名.databinding.XML文件去掉下划线首字母大写+Binding
例如,我的XML文件名称为activity_main.xml,通过DataBinding框架生成的包类名为:
com.dali.mvvmdemo.databinding.ActivityMainBinding;
其实,从这种简单的命名规则中也可以看出,通过DataBindingUtil.setContentView
将哪个xml文件绑定到activity,函数的返回值就是遵循了规则一的类实例。
那么binding类的命名就只能使用DataBinding框架生成的么?当然不是,DataBinding的<data>
标签中,可以定义当前xml生成binding类的类名。像这样:
<data class="CustomBinding">
<variable
name="person"
type="com.superli.mvvmdemo.User" />
</data>
class
的值就是自定义binding类的类名,它的固定类全名为:com.superli.mvvmdemo.databinding.CustomBinding;
这意味着,在所有使用到该类的地方,你需要添加的导入语句是:
import com.superli.mvvmdemo.databinding.CustomBinding;
比如在Activity中。
通过这个实例,我们可以直接操作xml文件中所有带id
的view
,而再也不用findViewById
了。
上述就是最简单的DataBinding的使用了,经过了这两步,你运行起来的APP,就可以说使用了DataBinding框架。我们来小结一下,基本步骤:
- 在Activity对应的XML文件中,在最外层包裹
<layout></layout>
标签,使DataBinding框架生成对应的binding类。 - 在activity中,通过
DataBindingUtil.setContentView
,将Xml以Binding实例的方式,提供给activity操作。
数据绑定
我们已经知道,在通过DataBindingUtil.setContentView
函数,获取了xml对应的binding实例之后,可以通过该实例操作xml文件。那么具体怎么做呢?
还是先从xml文件说起,前面提到,DataBinding的<layout></layout>
类似于一个命名空间,在该空间下,包含了一个<data></data>
标签和<variable/>
标签。看一下示例:
<?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"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="person"
type="com.dali.mvvmdemo.User" />
</data>
<!-- 其它布局代码 -->
</layout>
这里有两个陌生的标签:<data>
和 <variable>
-
<data>
标签:表示标签内的代码都将作为xml的binding类的一部分。 -
<variable>
标签:该标签中,申明了一个变量,和它对应的类。type表示类,name表示变量名,编译时,DataBinding将会把改变量申明到xml对应的binding类中。
那么,这段代码有啥用呢?
xml文件有了这段申明后,就可以在xml文件中自由的使用com.dali.mvvmdemo.User
类型的所有成员变量或者函数了,当然,还是得通过类的实例变量person
。
第一种绑定方法
一种比较典型的用法如下:
<TextView
android:id="@+id/tv_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text='@{String.valueOf(person.mAge), default="Default"}'
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_name"/>
使用“@{}”将需要使用的变量包裹起来,中间就可以像写Java代码一样使用了。因为这里的person.mAge
是int类型,所以使用String.valueOf
将数值类型转换成了字符串类型。
default="Default"
:表示,在布局文件预览时显示的值。
通常xml生成的binding类中,直接引用了java.lang包下的类,所以我们这里可以直接使用String类型,当基本类型无法满足你时,你可以通过
<import type="com.dali.mvvmdemo.User"/>
导入你需要的类型,当然,这部分暂时不开展。
User此时就是个简单的JavaBean类:
public class User {
public String mName;
public int mAge;
public User(String name, int age){
mName = name;
mAge = age;
}
}
绑定是绑定了,那么数据从哪儿来呢?看完下一个代码片段,你就明白了:
public class MainActivity extends AppCompatActivity {
private User user = new User("SuperLi", 3);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setPerson(user); // 将xml中的person变量和当前对象中的user变量绑定起来。
}
}
当xml的variable标签中,申明了变量名称后,DataBinding会在生成的xml binding类中,生成对应的setXXX
函数,以便将类实例的引用赋值给binding类中对应的变量XXX
。
例如:我的activity_main.xml的binding类是:ActivityMainBindingImpl,在activity_main.xml中有person变量申明如下:
<variable
name="person"
type="com.dali.mvvmdemo.User" />
那么,ActivityMainBindingImpl类中,将会生成如下代码:
public class ActivityMainBindingImpl extends ActivityMainBinding {
// ...
public void setPerson(@Nullable com.dali.mvvmdemo.User Person) {
this.mPerson = Person;
// ...
}
// ...
}
这是最常用最经典的绑定方式。
第二种常规方式
另外一种就是View
的Id
直接设置数据。还是以之前的xml代码为例:
<TextView
android:id="@+id/tv_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(person.mAge)}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_name"/>
TextView
的id为tv_age
,xml的binding类生成时,会有一个tvAge
的成员变量,通过它,可以操作当前TextView
,比如:
binding.tvAge.setText("1000");
和binding类名生成的规则类似,以下划线分割,第二个名字开始首字母大写。只不过TextView的id作为变量名称首字母小写,binding类作为类名首字母大写而已。