Skip to content

数据绑定

前面讲述了如何开始使用dataBinding。 本文讲述数据改变UI,动态更新的相关做法。

使用Observable

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

继承BaseObservable

假设我们有一个类SysInfo,代表着我们业务上的数据。

public class SysInfo {
    private String info1 = Build.MANUFACTURER;
    private String timeStr = "";
    private long time;

    // getter setter
}

让它继承BaseObservable类,并给get方法添加@Bindable注解。

public class SysInfo extends BaseObservable {

    private String info1 = Build.MANUFACTURER;
    private String timeStr = "";
    private long time;

    @Bindable
    public String getInfo1() {
        return info1;
    }

    public void setInfo1(String info1) {
        this.info1 = info1;
        notifyPropertyChanged(BR.info1);
    }

    @Bindable
    public String getTimeStr() {
        return timeStr;
    }

    public void setTimeStr(String timeStr) {
        this.timeStr = timeStr;
        notifyPropertyChanged(BR.timeStr);
    }

    @Bindable
    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time = time;
        notifyPropertyChanged(BR.time);
    }
}

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

定义一个工具类DataUtils,提供静态方法。

public class DataUtils {
    private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);

    public static String formatTime(long time) {
        return format.format(time);
    }
}

layout布局

在data标签下可以使用多个import标签,把需要使用的类导入进来。 引入工具类DataUtils,声明使用SysInfo对象。

android:text中使用的是@{}表达方式。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <import type="com.rustfisher.tutorial2020.databinding.DataUtils" />

        <variable
            name="info"
            type="com.rustfisher.tutorial2020.databinding.data.SysInfo" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{info.info1}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{info.timeStr}" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{DataUtils.formatTime(info.time)}" />
    </LinearLayout>
</layout>

除了直接使用对象的属性,还可以直接在xml中做一些操作,例如@{DataUtils.formatTime(info.time)}

如果在xml中使用了错误的类型,例如给TextView的text设置了long类型的属性,会在编译时报错。

Found data binding errors. data binding error msg:Cannot find the setter for attribute 'android:text' with arameter type long on android.widget.TextView.

Activity代码

在activity中,把SysInfo对象交给binding。 开启一个定时器去更新数据。

public class DataBindingAct1 extends AbsActivity {

    private ActDataBinding1Binding binding;
    private SysInfo mSysInfo = new SysInfo();

    private Timer mTimer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = DataBindingUtil.setContentView(this, R.layout.act_data_binding_1);
        binding.setInfo(mSysInfo);

        mTimer = new Timer();
        mTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                mSysInfo.setTimeStr("Time: " + System.currentTimeMillis());
                mSysInfo.setTime(System.currentTimeMillis());
            }
        }, 0, 500);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mTimer.cancel();
    }
}

运行后可以发现,数据是动态变化的。