Android DataBinding扫盲篇(一)

·  阅读 600

这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战

Android DataBinding扫盲篇(一)

前几天和朋友探讨小程序上的问题,发现居然也是使用的双向绑定的模式,我就说,我们大Android很早就有双向绑定啊。这篇文章记录实现数据绑定的过程,给没有接触过的数据绑定的同学一点帮助。

一、DataBinding是什么

简单的来说,DataBinding是一个实现数据和UI绑定的支持库,同时也是实现MVVM模式所依赖的工具。

该库在2015年就已经诞生了,MVVM的盛行使得更多人了解它,后来发现很多前端框架中也有数据绑定这种技术,比如我看到的小程序是这么写的:

_this.setData({
  treeData:[item]
}) 

复制代码
 <view list='{{treeData}}' />
复制代码

这种写法就和 Android 中的写法很相似了,也许这些语言学到深处,都是相通的。

二、实现简单的DataBinding

DataBinding是MVVM架构所依赖的工具;可以省掉findViewById的操作。

2.1 开启DataBinding

我们仅需要在modulebuild.gradle中进行开启即可,示例代码

android {
    compileSdkVersion 28
    buildToolsVersion "28.0.3"
    
    ...
    
    // 启用dataBinding
    dataBinding{
        enabled true
    }
}
复制代码

2.2 新建一个对象

没什么好说的,一个普通的对象

public class Person {

    private int id;
    private String name;
    private String sex;

    public Person() {
    }

    public Person(int id, String name, String sex) {
        this.id = id;
        this.name = name;
        this.sex = sex;
    }
    
    // get set
}
复制代码

2.3 修改布局文件

将layout文件更改,使其符合数据绑定的规则。

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

   <!--  增加部分-->
    <data class="MainBinding">
        <variable
            name="person"
            type="com.demo.mvvmdemo.Person" />
    </data>

    <!--  原有layout部分-->

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

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(person.id)}" />

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

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

    </LinearLayout>

</layout>
复制代码

重点是增加了<data>这个标签,class是指定了绑定后的名称,在activity中获取,不明白就接着看。 其中android:text="@{String.valueOf(person.id)} 对应着我们创建对象的id的属性。

2.4 创建对应的Activity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
        MainBinding mainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        Person person = new Person(1, "张三", "男");
        mainBinding.setPerson(person);

    }
}
复制代码

将原始的setContentView换成上诉代码中的显示方式。其中MainBinding就对应着layout中的<data class="MainBinding">, 如果不指定class,默认的就是layout的名字加上‘Binding’,比如获取activity_layout.xml,就是ActivityMainBinding

setPerson 是将对象绑定。

至此,一个简单的数据绑定就已经完成了。

三、即时更改UI

上面的代码虽然已经实现了数据绑定,但我们每次更改数据,想要更新页面时,都需要重新调用setData(Object)来更新试图,这样显然不太方便。

怎么实现一次绑定,随时更新数据即更新试图呢

这种场景第一就想到观察者模式,看看是怎么实现的。

3.1 单向绑定方式一、继承BaseObservable

  1. 让对象继承BaseObservable
  2. 在每一个get方法上方加上 @Bindable
  3. 在每一个set方法中加入notifyPropertyChanged(BR.对应的属性)

代码示例

public class Person extends BaseObservable {

    private int id;
    private String name;
    private String sex;

    public Person() {
    }

    public Person(int id, String name, String sex) {
        this.id = id;
        this.name = name;
        this.sex = sex;
    }

    @Bindable
    public int getId() {
        return id;
    }


    public void setId(int id) {
        this.id = id;
        notifyPropertyChanged(BR.id);
    }

    @Bindable
    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }

    @Bindable
    public String getSex() {
        return sex;
    }


    public void setSex(String sex) {
        this.sex = sex;
        notifyPropertyChanged(BR.sex);
    }
}

复制代码

Activity

public class MainActivity extends AppCompatActivity {
    Person person;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
        final ActivityMainBinding mainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        person = new Person(1, "张三", "男");
        mainBinding.setPerson(person);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                person.setId(2);
                person.setName("李四");
                person.setSex("女");
            }
        },2000);

    }
}
复制代码

延迟两秒刷新数据,在两秒后,更新的对象的属性,可以看到界面也刷新了。

3.1 单向绑定方式二、定义ObserverField对象

  1. 改变了实体类的属性。
  2. 设置属性时方法也变化了。
person.getId().set(2);
person.getName().set("李四");
person.getSex().set("女");
复制代码

直接看代码吧。

实体类

public class Person {

    public ObservableField<Integer> id = new ObservableField<>();
    public ObservableField<String> name = new ObservableField<>();
    public ObservableField<String> sex = new ObservableField<>();

    public ObservableField<Integer> getId() {
        return id;
    }

    public void setId(ObservableField<Integer> id) {
        this.id = id;
    }

    public ObservableField<String> getName() {
        return name;
    }

    public void setName(ObservableField<String> name) {
        this.name = name;
    }

    public ObservableField<String> getSex() {
        return sex;
    }

    public void setSex(ObservableField<String> sex) {
        this.sex = sex;
    }
}

复制代码

Activity

public class MainActivity extends AppCompatActivity {
    Person person;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
        final ActivityMainBinding mainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        person = new Person();
        mainBinding.setPerson(person);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                person.getId().set(2);
                person.getName().set("李四");
                person.getSex().set("女");
            }
        },2000);

    }
}
复制代码

可以看到,两种方式最后的效果是一致的。

分类:
Android
标签: