跳转至

数据绑定

更新日期 2022-9-1
  • 2022-9-1 更新格式
  • 2021-6-26 创建文档

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

使用Observable

DataBinding提供了Observable接口用于监听实体类对象属性的变化,Observable接口有具有添加、删除监听的功能。

为了简化开发,DataBinding已经为我们实现了一个基本的监听类BaseObservable,实体类只要继承BaseObservable,然后在get方法上加入@Bindable注解,set方法中调用notifyPropertyChanged通知UI更新就可以了。

继承BaseObservable

假设我们有一个类SysInfo,代表着我们业务上的数据。这里用一些系统信息来演示。

SysInfo.java
public class SysInfo {
    private String info1 = Build.MANUFACTURER;
    private String timeStr = "";
    private long time;
    // getter setter
}

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

SysInfo继承BaseObservable类
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);
    }
}

此时SysInfo类已经是“可被观测”的了。

set方法里我们都主动调用了notifyPropertyChanged。 在get方法上加入@Bindable注解后,编译一下工程,DataBinding就会在BR文件中生成相应的字段。

BR是编译期间生成的类,类似于R文件

定义一个工具类DataUtils,提供静态方法。这个方法后面会在layout中用到。

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标签,把需要使用的类导入进来。

  • 引入(import)工具类DataUtils
  • 声明(variable)使用SysInfo对象。变量名定为info
  • 给TextView设置显示的字符 android:text="@{info.timeStr}",其中使用的是@{}表达方式。
  • 使用工具类DataUtils的方法,使用的也是@{}
layout
<?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代码

之前我们在layout中设置了SysInfo变量,binding会自动生成binding.setInfo()方法。

在activity中,我们创建一个SysInfo对象,交给binding。后面这个对象的数据发生改变时,界面会相应地改变。

为了演示数据变化,我们开启一个定时器去更新数据。

DataBindingAct1
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();
    }
}

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

本文介绍的是界面监听实体类对象属性变化的方法。

有兴趣的读者朋友可以尝试一下,binding.setInfo(mSysInfo);后,重新创建mSysInfo,看看界面还会不会动态变化。

在这个例子中,set方法里要主动调用notifyPropertyChanged方法。有没有更简单的方式呢?

接下来我们看可观察数据对象ObservableField的用法

🧑🏻‍💻 示例代码

本站说明

一起在知识的海洋里呛水吧。广告内容与本站无关。如果喜欢本站内容,欢迎投喂作者,谢谢支持服务器。如有疑问和建议,欢迎在下方评论~

📖AndroidTutorial 📚AndroidTutorial 🙋反馈问题 🔥最近更新 🍪投喂作者

Ads