封面

DataBinding是一个实现数据和UI绑定的框架,同时也是实现MVVM模式所依赖的工具。

官方文档

Demo下载地址

1.构建环境

在app根目录的build.gradle文件中加入DataBinding配置:

android {    ....    dataBinding {        enabled = true    }}

环境要求:

  • 系统版本:Android 2.1(API level 7)及以上

  • Gradle版本:1.5.0-alpha1及以上

  • Android Studio版本:1.3及以上

2.基本使用

布局文件

DataBinding的布局文件使用了layout标签作为根节点,其中包含了data标签与view标签,view标签的内容就是不使用DataBinding时的普通布局内容:

<?xml version="1.0" encoding="utf-8"?>                                        

data标签下的user变量定义了可以在此布局中使用的属性:

    

布局中的表达式使用了@{ }语法:

数据实体

public class User {    private String firstName;    private String lastName;    public User(String firstName, String lastName) {        this.firstName = firstName;        this.lastName = lastName;    }    public String getFirstName() {        return firstName;    }    public void setFirstName(String firstName) {        this.firstName = firstName;    }    public String getLastName() {        return lastName;    }    public void setLastName(String lastName) {        this.lastName = lastName;    }}

数据绑定

默认情况下,DataBinding会根据布局文件名称自动生成ActivityBaseUseBinding类(activity_base_use -> ActivityBaseUseBinding)。

public class BaseUseActivity extends AppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // ActivityBaseUseBinding是根据布局名称自动生成的        // 代替原来的setContentView(R.layout.activity_base_use)方法        ActivityBaseUseBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_base_use);        User user = new User("容华", "谢后");        // set方法是根据data标签下的variable名称自动生成的        binding.setUser(user);    }}

3.布局详情

导入

在data标签下可以使用多个import标签,就像Java一样把类导入到布局文件中:

    

当类名冲突时可以设置别名:

导入的类型也可以用于变量的类型引用和表达式中:

                

< >需要使用转义字符< >代替。

在表达式中使用静态方法:

public class StringUtils {    public static String capitalize(String word) {        if (word.length() > 1) {            return String.valueOf(word.charAt(0)).toUpperCase() + word.substring(1);        }        return word;    }}
        

和在Java中一样,java.lang. 会被自动导入。*

自定义绑定类名

默认情况下,Binding的类名是根据布局文件名称命名的,假如包名是com.yl.databindingdemo,那么Binding类就会被放在com.yl.databindingdemo.databinding包下,如果不想使用默认类名和路径,可以进行自定义修改:

    ...    ...    ...

Includes

变量可以传递到include布局中:

<?xml version="1.0" encoding="utf-8"?>                                

layout_include布局中也需要声明user变量:

<?xml version="1.0" encoding="utf-8"?>                                        

注意:DataBinding不支持使用merge节点。

表达式语法

支持的表达式:

  • 数学计算 + - / * %

  • 字符串连接 +

  • 逻辑 && ||

  • 二进制 & | ^

  • 一元运算符 + - ! ~

  • 位移 >> >>> <<

  • 比较 == > < >= <=

  • instanceof

  • 组 ()

  • 文字 - 字符,字符串,数字, null

  • 类型转换

  • 函数调用

  • 字段存取

  • 数组存取 []

  • 三目运算符 ?:

例如:

android:text="@{String.valueOf(index + 1)}"android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"android:transitionName='@{"image_" + id}'

不支持的表达式:

  • this

  • super

  • new

  • 显式泛型调用

Null合并运算符

非null时选择左边的操作,反之选择右边的操作:

android:text="@{user.displayName ?? user.lastName}"

等价于:

android:text="@{user.displayName != null ? user.displayName : user.lastName}"

集合

通用的集合类(arrays, lists, sparse lists, maps),可以使用[ ]操作符来存取:

                                …android:text="@{list[index]}"…android:text="@{sparse[index]}"…android:text="@{map[key]}"

如果属性使用单引号的话,表达式就可以使用双引号:

android:text='@{map["firstName"]}'

属性使用双引号,表达式可以使用以下两种方式:

android:text="@{map[`firstName`}"android:text="@{map['firstName']}"

资源

可以在表达式中使用普通语法来引用资源:

%1$s %2$sandroid:text="@{@string/full_name(user.firstName, user.lastName)}"

部分资源的表达式引用和普通引用有所不同:

Type Normal Reference Expression Reference
String[] @array @stringArray
int[] @array @intArray
TypedArray @array @typedArray
Animator @animator @animator
StateListAnimator @animator @stateListAnimator
color int @color @color
ColorStateList @color @colorStateList

4.动态更新

在上面的例子中,如果修改实体类的数据,UI是不会动态更新的,别担心,DataBinding为我们提供了一套很Nice的通知机制:

Observable Objects

DataBinding提供了Observable接口用于监听实体类对象属性的变化,Observable接口有具有添加、删除监听的功能。为了简化开发,DataBinding已经为我们实现了一个基本的监听类BaseObservable,实体类只要继承BaseObservable,然后在get方法上加入@Bindable注解,set方法中调用notifyPropertyChanged通知UI更新就可以了。

public class ObservableObjectsUser extends BaseObservable {    private String firstName;    private String lastName;    public ObservableObjectsUser() {    }    public ObservableObjectsUser(String firstName, String lastName) {        this.firstName = firstName;        this.lastName = lastName;    }    @Bindable    public String getFirstName() {        return firstName;    }    public void setFirstName(String firstName) {        this.firstName = firstName;        notifyPropertyChanged(BR.firstName);    }    @Bindable    public String getLastName() {        return lastName;    }    public void setLastName(String lastName) {        this.lastName = lastName;        notifyPropertyChanged(BR.lastName);    }}

在get方法上加入@Bindable注解后,DataBinding就会在BR文件中生成相应的字段,BR是编译期间生成的类,类似于R文件。

在Activity中动态更新UI:

public class ObservableActivity extends AppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        ActivityObservableBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_observable);        final ObservableObjectsUser user = new ObservableObjectsUser("容华", "谢后");        binding.setUser(user);        binding.setClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                user.setFirstName("空谷");                user.setLastName("幽兰");            }        });    }}

看下效果:

动态更新

ObservableFields

每个get方法都要加上注解,还要在每个set方法中通知UI更新,是不是有点麻烦,贴心的DataBinding还为我们提供了更简便的方式:

public class ObservableFieldsUser {    public ObservableField firstName = new ObservableField<>();    public ObservableField lastName = new ObservableField<>();    public ObservableFieldsUser(String firstName, String lastName) {        this.firstName.set(firstName);        this.lastName.set(lastName);    }}

在Activity中动态更新UI:

public class ObservableActivity extends AppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        ActivityObservableBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_observable);        final ObservableFieldsUser user = new ObservableFieldsUser("容华", "谢后")        binding.setUser(user);        binding.setClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                user.firstName.set("空谷");                user.lastName.set("幽兰");        });    }}

除了ObservableField,还可以使用ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, ObservableParcelable。

Observable Collections

不一定使用实体类才能动态更新,DataBinding还为我们提供了更灵活的方式:

public class ObservableActivity extends AppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        ActivityObservableBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_observable);        final ObservableArrayMap user = new ObservableArrayMap<>();        user.put("firstName", "容华");        user.put("lastName", "谢后");        binding.setUser(user);        binding.setClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                user.put("firstName", "空谷");                user.put("lastName", "幽兰");            }        });    }}

布局文件:

<?xml version="1.0" encoding="utf-8"?>                                                            

5.双向绑定

DataBinding现在也支持双向绑定了,即UI改变的同时,数据模型中的数据也跟着改变:

<?xml version="1.0" encoding="utf-8"?>                                        

使用@={ }表达式进行双向绑定,看下效果:

双向绑定

6.事件处理

类似于android:onClick可以指定Activity中的方法,DataBinding也提供了事件处理的机制:

  • 方法调用:方法的参数必须与监听对象的参数相匹配,比如点击事件onClick(View v),对应的方法必须为methodName(View v)。

  • 监听绑定:只要方法的返回值与监听对象的返回值相匹配就可以,比如onLongClick(View v)的返回值是boolean类型的,那么对应的方法返回值也必须是boolean类型的。

方法调用

表达式会在编译时处理,如果方法不存在,编译将会报错。

public class EventHandler {    public void onClickFriend(View view) {        Toast.makeText(view.getContext(), "onClickFriend", Toast.LENGTH_LONG).show();    }}

布局文件:

<?xml version="1.0" encoding="utf-8"?>                            

@{handler::onClickFriend}代表调用EventHandler类中的onClickFriend方法,注意onClickFriend方法的参数必须与onClick(View v)方法的参数相匹配。

监听绑定

官方文档上的说明是:监听绑定在事件发生时调用,可以使用任意表达式。测试过程中发现如果方法不存在,编译也会报错。

注意:需要在Android Gradle Plugin version 2.0版本以上使用。

public class EventHandler {    public void onTaskClick(Task task) {        task.run();    }    public void onTaskClick(View view, Task task) {        Toast.makeText(view.getContext(), "onTaskClick", Toast.LENGTH_LONG).show();        task.run();    }    public void onCompletedChanged(Task task, boolean completed) {        if (completed) {            task.run();        }    }}public class Task implements Runnable {    private static final String TAG = "Task";    @Override    public void run() {        Log.i(TAG, "Task running");    }}

布局文件:

<?xml version="1.0" encoding="utf-8"?>                                    

lambda表达式中的参数有两种选择,全不写或者全写,例如onCheckedChanged(CompoundButton buttonView, boolean isChecked)方法有两个参数,如果用到其中一个参数,另一个参数也要补上,不能只写一个,参数名称可以自定义。

7.写在最后

源码已托管到GitHub上,欢迎Fork,觉得还不错就Start一下吧!

GitHub传送门

欢迎同学们吐槽评论,如果你觉得本篇博客对你有用,那么就留个言或者点下喜欢吧(^-^)

在下一篇文章中我们将会学习一下DataBinding的其他用法,例如如何在RecyclerView中使用DataBinding,如何自定义属性等,敬请期待!

《Android DataBinding使用详解(二)》

更多相关文章

  1. Material Design——控件大汇总(二)
  2. 使用 SQLiteDatabase 操作 SQLite 数据库
  3. Android(安卓)底部支付弹窗
  4. Android(安卓)studio 中与本地 html 页面交互
  5. Android(安卓)开发者必知必会的权限管理知识
  6. AndroidStudio上面最好用的插件
  7. 真机上使用Hierarchy Viewer
  8. Android(安卓)studio 命令gradlew assembleRelease打包时,出现 Un
  9. android关闭应用程序

随机推荐

  1. TextUtils类介绍
  2. android Eclipse导入com.android.interna
  3. Android、java环境搭建流程
  4. Android(安卓)SQLiteOpenHelper的使用
  5. Android各个版本的区别
  6. Android可以在子线程更新UI吗
  7. 【android】HandlerThread的使用及源码剖
  8. Android原始视频格式YUV,NV12,NV21,YV12,YU
  9. Android(安卓)Studio 布局中引用自定义属
  10. Android(安卓)Dialog,Toast封装