Skip to content

使用可观察数据对象

可观察性是指一个对象将其数据变化通知给其他对象的能力。通过数据绑定库,您可以让对象、字段或集合变为可观察。

任何 plain-old 对象都可用于数据绑定,但修改对象不会自动使界面更新。通过数据绑定,数据对象可在其数据发生更改时通知其他对象,即监听器。可观察类有三种不同类型:对象、字段和集合。

当其中一个可观察数据对象绑定到界面并且该数据对象的属性发生更改时,界面会自动更新。

可观察字段

在创建实现 Observable 接口的类时要完成一些操作,但如果您的类只有少数几个属性,则这样操作的意义不大。在这种情况下,您可以使用通用 Observable 类和以下特定于基元的类,将字段设为可观察字段: - ObservableBoolean - ObservableByte - ObservableChar - ObservableShort - ObservableInt - ObservableLong - ObservableFloat - ObservableDouble - ObservableParcelable

可观察字段是具有单个字段的自包含可观察对象。 原语版本避免在访问操作期间封箱和开箱。要使用此机制,请采用 Java 编程语言创建 public final 属性,或在 Kotlin 中创建只读属性,如以下示例所示:

    private static class User {
        public final ObservableField<String> firstName = new ObservableField<>();
        public final ObservableField<String> lastName = new ObservableField<>();
        public final ObservableInt age = new ObservableInt();
    }

要访问字段值,请使用 set()get() 访问器方法,如下所示:

    user.firstName.set("Google");
    int age = user.age.get();

使用ObservableField

使用Observable的时候,我们在每个set方法里,都调用notifyPropertyChanged去通知ui。 我们也可以换用ObservableField来实现动态更新。

新建类SysInfoObs,里面使用ObservableField<T>

public class SysInfoObs {
    public ObservableField<String> info1 = new ObservableField<>(Build.MANUFACTURER);
    public ObservableField<String> timeStr = new ObservableField<>();
    public ObservableField<Long> time = new ObservableField<>();
}

layout和上面的差不多。引入的variable type改为我们新建的SysInfoObs类。

<?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.SysInfoObs" />
    </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>

activity中修改一下使用方式。新建DataBindingAct2类,持有SysInfoObs的对象。

public class DataBindingAct2 extends AbsActivity {

    private ActDataBinding2Binding binding;
    private SysInfoObs mSysInfo = new SysInfoObs();

    private Timer mTimer;

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

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

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

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

要更新数据时,需要调用ObservableField的set方法。 运行起来就可以看到更新UI的效果了。

可观察集合

某些应用使用动态结构来保存数据。可观察集合允许使用键访问这些结构。 当键为引用类型(如 String)时,ObservableArrayMap 类非常有用,如以下示例所示:

ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Rust");
user.put("lastName", "Fisher");
user.put("age", 18);
binding.setUser(user);

在布局中,可使用字符串键找到Map,如下所示:

    <data>
        <import type="androidx.databinding.ObservableArrayMap" />
        <variable
            name="user"
            type="ObservableArrayMap&lt;String, Object>" />
    </data>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text='@{user.firstName + " " + user.lastName}' />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(1 + (Integer)user.age)}" />

注意Map的左尖括号要改写为&lt;

使用 ObservableArrayList 类,如下所示:

ObservableArrayList<Object> obList = new ObservableArrayList<>();
obList.add("Rust");
obList.add("Fisher");
obList.add("Android");
obList.add(2020);
binding.setObList(obList);

在layout中进行设置

    <data>
        <import type="androidx.databinding.ObservableArrayList" />

        <variable
            name="obList"
            type="ObservableArrayList&lt;Object>" />
    </data>

    <!-- .... -->

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text='@{obList[0] + " " + obList[1]}' />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text='@{String.valueOf(1 + (Integer)obList[3])}' />