MVVM&Android实践(一):DataBinding入门


了解DataBinding的使用,请参考:

官网

如果你暂时无法翻墙,看这篇文章也可以。

本文中,默认的View就是Activity及其对应的XML文件。

第一部分:DataBinding入门

配置项

在Android中,需要使用DataBinding来支持MVVM的双向绑定。

在Android中的DataBinding需要在module下的build.gradle中申明:

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

Layout标签使用

想让DataBinding生效,还需要在View对应的XML中间中使用layout标签,它就像个命名空间一样。类似于:

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

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

在这个layout标签包裹的命名空间下,有一个data标签,你可以通过该标签,在View的XML文件中引入Model的变量,这个留在后面说。

我们前面说了在MVVM中,Activity和对应的XML文件共同组成了View,那么它们是怎么联系到一起得呢?

一般来说,XML文件,通过Activity的setContentView函数,将XML文件,交给Activity控制。就像这样:

setContentView(R.layout.activity_main);

那么,在DataBinding框架下,我们得换个新得姿势:

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

setContentView的函数名相同,但调用实例却从传统的Activity换成了DataBindingUtil的静态函数。

聪明的小伙伴已经注意到了,为啥莫名其妙多了个ActivityMainBinding类?这不是我干的!!!!解释一下。

当你在XML文件中正确的添加了<layout></layout>标签时,AndroidStudio会通过DataBinding框架,自动生成了一个类,这个类的包名遵循如下规则:

规则一:项目包名.databinding.XML文件去掉下划线首字母大写+Binding

例如,我的XML文件名称为activity_main.xml,通过DataBinding框架生成的包类名为:

com.dali.mvvmdemo.databinding.ActivityMainBinding;

其实,从这种简单的命名规则中也可以看出,通过DataBindingUtil.setContentView将哪个xml文件绑定到activity,函数的返回值就是遵循了规则一的类实例。

那么binding类的命名就只能使用DataBinding框架生成的么?当然不是,DataBinding的<data>标签中,可以定义当前xml生成binding类的类名。像这样:

<data class="CustomBinding">
    <variable
              name="person"
              type="com.superli.mvvmdemo.User" />
</data>

class的值就是自定义binding类的类名,它的固定类全名为:com.superli.mvvmdemo.databinding.CustomBinding; 这意味着,在所有使用到该类的地方,你需要添加的导入语句是:

import com.superli.mvvmdemo.databinding.CustomBinding;

比如在Activity中。

通过这个实例,我们可以直接操作xml文件中所有带idview,而再也不用findViewById了。

上述就是最简单的DataBinding的使用了,经过了这两步,你运行起来的APP,就可以说使用了DataBinding框架。我们来小结一下,基本步骤:

  1. 在Activity对应的XML文件中,在最外层包裹<layout></layout>标签,使DataBinding框架生成对应的binding类。
  2. 在activity中,通过DataBindingUtil.setContentView,将Xml以Binding实例的方式,提供给activity操作。

数据绑定

我们已经知道,在通过DataBindingUtil.setContentView函数,获取了xml对应的binding实例之后,可以通过该实例操作xml文件。那么具体怎么做呢?

还是先从xml文件说起,前面提到,DataBinding的<layout></layout>类似于一个命名空间,在该空间下,包含了一个<data></data>标签和<variable/>标签。看一下示例:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    
    <data>
        <variable
            name="person"
            type="com.dali.mvvmdemo.User" />
    </data>
	<!-- 其它布局代码 -->
</layout>

这里有两个陌生的标签:<data><variable>

  • <data>标签:表示标签内的代码都将作为xml的binding类的一部分。
  • <variable>标签:该标签中,申明了一个变量,和它对应的类。type表示类,name表示变量名,编译时,DataBinding将会把改变量申明到xml对应的binding类中。

那么,这段代码有啥用呢?

xml文件有了这段申明后,就可以在xml文件中自由的使用com.dali.mvvmdemo.User类型的所有成员变量或者函数了,当然,还是得通过类的实例变量person

第一种绑定方法

一种比较典型的用法如下:

<TextView
          android:id="@+id/tv_age"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text='@{String.valueOf(person.mAge), default="Default"}'
          app:layout_constraintBottom_toBottomOf="parent"
          app:layout_constraintLeft_toLeftOf="parent"
          app:layout_constraintRight_toRightOf="parent"
          app:layout_constraintTop_toBottomOf="@id/tv_name"/>

使用“@{}”将需要使用的变量包裹起来,中间就可以像写Java代码一样使用了。因为这里的person.mAge是int类型,所以使用String.valueOf将数值类型转换成了字符串类型。

default="Default":表示,在布局文件预览时显示的值。

通常xml生成的binding类中,直接引用了java.lang包下的类,所以我们这里可以直接使用String类型,当基本类型无法满足你时,你可以通过<import type="com.dali.mvvmdemo.User"/>导入你需要的类型,当然,这部分暂时不开展。

User此时就是个简单的JavaBean类:

public class User {
    public String mName;
    public int mAge;

    public User(String name, int age){
        mName = name;
        mAge = age;
    }
}

绑定是绑定了,那么数据从哪儿来呢?看完下一个代码片段,你就明白了:

public class MainActivity extends AppCompatActivity {
    private User user = new User("SuperLi", 3);
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setPerson(user); // 将xml中的person变量和当前对象中的user变量绑定起来。
    }
}

当xml的variable标签中,申明了变量名称后,DataBinding会在生成的xml binding类中,生成对应的setXXX函数,以便将类实例的引用赋值给binding类中对应的变量XXX

例如:我的activity_main.xml的binding类是:ActivityMainBindingImpl,在activity_main.xml中有person变量申明如下:

<variable
    name="person"
    type="com.dali.mvvmdemo.User" />

那么,ActivityMainBindingImpl类中,将会生成如下代码:

public class ActivityMainBindingImpl extends ActivityMainBinding  {
	// ...
	public void setPerson(@Nullable com.dali.mvvmdemo.User Person) {
        this.mPerson = Person;
        // ...
    }
    // ...
}

这是最常用最经典的绑定方式。

第二种常规方式

另外一种就是ViewId直接设置数据。还是以之前的xml代码为例:

<TextView
          android:id="@+id/tv_age"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{String.valueOf(person.mAge)}"
          app:layout_constraintBottom_toBottomOf="parent"
          app:layout_constraintLeft_toLeftOf="parent"
          app:layout_constraintRight_toRightOf="parent"
          app:layout_constraintTop_toBottomOf="@id/tv_name"/>

TextView的id为tv_age,xml的binding类生成时,会有一个tvAge的成员变量,通过它,可以操作当前TextView,比如:

binding.tvAge.setText("1000");

和binding类名生成的规则类似,以下划线分割,第二个名字开始首字母大写。只不过TextView的id作为变量名称首字母小写,binding类作为类名首字母大写而已。

发布了79 篇原创文章 · 获赞 30 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章