DataBinding使用教程(二):xml标签详解

阅读 187
收藏 10
2017-09-12
原文链接:blog.csdn.net

到底有哪些可用的DataBinding标签

DataBinding总共有如下几个标签可以使用,一些标签下还有一些属性可以更具体的控制这些标签:
- layout标签
- data标签:class属性
- variable标签:type属性、name属性
- import标签:type属性、alias属性

这些标签以及属性的定义和使用都可以在compilerCommon这个jar包中的android/databinding/tool/store/LayoutFileParser.java这个类中找到。

不知道compilerCommon这个jar包是什么或者怎么下载这个jar包的可以看看我的上篇文章DataBinding使用教程(一):配置与基本使用

layout标签

如果想使用DataBinding开发的话,必须要在原有布局的最外层包裹一层layout标签,即layout标签是整个布局的根标签。

注意事项

  • layout标签内部只能有一个直接子view,多于1个就会报错,这个和ScrollView的要求是类似的。
  • 记得把android和app的命名空间提升到layout标签中
  • layout标签的直接子标签不能是merge,否则报错。
  • fragment标签不支持dataBinding表达式,即在fragment标签中使用任何dataBinding表达式都会报错,即如下使用方式是错误的:
<?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">

    <data>
        <variable
            name="tag"
            type="String"/>
    </data>

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

        <fragment
            android:id="@+id/fragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:tag="@{tag}"/>
    </LinearLayout>
</layout>

错误信息如下:
fragment错误信息

在源码中也可以看到当解析到fragment标签且这个fragment标签还使用了dataBinding表达式时,就会跳过fragment标签并且报错。源码如下:

...

else if ("fragment".equals(nodeName)) {
    if (XmlEditor.hasExpressionAttributes(parent)) {
        L.e("fragments do not support data binding expressions.");
    }
    continue;
}

...

data标签

顾名思义,data标签的作用就是用来承载数据的,在data标签内部可以定义多个import标签和variable标签。

注意事项

  • data标签最多只能有一个,多于一个则报错
    错误信息

class属性的作用和用法

data标签有个class属性,用于定义生成的Binding类的规则。该属性不是必填属性,如果不填则采用默认的Binding类生成规则,如果要填,则会根据你填写内容的格式不同而有不同的生成规则。

作用
  • 控制生成的Binding类的名称
  • 控制生成的Binding类所在的路径
用法
  • 默认情况:即不使用class属性
<?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">

    <data>

    </data>

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

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"/>
    </LinearLayout>
</layout>

生成规则为:
在项目包名下先生成databinding文件夹,然后在databinding文件夹中根据布局文件的名称生成Binding类。

根据布局文件的名称生成Binding类的规则为:以大写形式开始,删除下划线(_),并使用驼峰命名,然后后缀为“Binding”。

比如我的项目包名为:com.qiangxi.databindingdemo,布局文件名称为:activity_xml_label,则生成的binding类的名称及结构如下图所示:
默认生成规则

  • 使用class属性:class=”customClassName”
    生成规则为:
    在项目包名下先生成databinding文件夹,然后在databinding文件夹中生成customClassName类.
    class="customClassName"

  • 使用class属性:class=”.customClassName”
    生成规则为:
    直接在项目包名下生成customClassName类.而不会再生成databinding文件夹
    class="customClassName"

  • 使用class属性:class=”cn.rqq.customClassName”
    生成规则为:
    直接创建cn.rqq包名,然后在cn/rqq/文件夹下生成customClassName类
    class="customClassName"

生成文件所在路径:app Module/build/generated/source/apt/debug文件夹下,根据你自己定义的生成规则去找即可。

variable标签

variable标签是整个DataBinding机制的核心之一,是联系java代码和xml布局的纽带。variable标签定义在data标签内部,在data标签中,可以定义多个variable标签,每个variable标签的name属性值不可相同,但type属性值可以相同。

type属性(必填):

用于定义数据源所在路径,比如定义User实体类,要定义User的完整类名。具体见下面的示例。

name属性(必填):

用于定义数据源的名称,在遵循基本命名规则的前提下,随意命名,但建议使用有意义的名称。具体见下面的示例。可以用name属性的值引用所属类的字段或方法.

variable的作用

variable是变量的意思,顾名思义,variable标签就是用来定义“变量”的,这些“变量”就是数据源,但不只限于提供数据源,variable标签有如下作用: - 定义String,Integer,Long等包装类型的数据【包括对应的基本类型】,对于包装类型的数据可以不用填写完整类名,因为DataBinding已经自动帮我们导入了java.lang的包了。当然你硬要使用完整类名也可以。

...

<data>
    <variable
        name="name"
        type="java.lang.String"/>

    <variable
        name="age"
        type="int"/>

    <variable
        name="sex"
        type="String"/>
</data>

...
  • 定义实体数据,需要导入完整类名
...

<data>
     <variable
        name="user"
        type="com.qiangxi.databindingdemo.entity.User"/>
</data>

...
  • 定义其他类(非数据类),比如activity中定义的监听方法;需要导入完整类名
<?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">

    <data>
        <variable
            name="presenter"
            type="com.qiangxi.databindingdemo.acitivity.XmlLabelActivity"/>
    </data>

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

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:onClick="@{() -> presenter.onViewClick()}"/>
    </LinearLayout>
</layout>

import标签

import标签用于导入包,让我们可以直接使用某个类的静态方法或静态字段。

type属性(必填):

该属性的作用和variable标签类似,用于指定导入类的全路径。

alias属性(可选):

当多个import标签的type属性值相同时,如果不做区分,在编译时会报错,因为默认情况下,它们之间的别名都是相同的,为了能正常编译运行,就需要使用alias属性做区分。

<?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">

    <data>

        <import
            alias="textUtils01"
            type="android.text.TextUtils"/>

        <import
            alias="textUtils02"
            type="android.text.TextUtils"/>
    </data>

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

        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"/>
    </LinearLayout>
</layout>

到此,DataBinding相关的xml标签就讲完了,这些标签之间相互配合就可以实现各种需求。

一些相关的小知识点

1. 自动导入Context对象

根据上面的内容,我们知道variable标签需要定义name属性,定义完毕之后,我们就可以根据这个name的名称进行相关方法调用. 其中context这个名称就是dataBinding通过variable标签默认帮我们定义的,该context的值就是从当前布局文件中的根节点view的getContext()方法获取的.所以我们可以在布局中直接引用context,进而调用context的相关方法:

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

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

        <TextView
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_marginTop="3dp"
            android:gravity="center_vertical"
            android:text="@{context.getApplicationInfo().toString()}"
            />
    </LinearLayout>
</layout>

但是如果我们自己通过variable标签定义了一个name为context的对象,那么会覆盖掉系统提供的context:

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

    <data>

        <import type="android.view.View"/>

        <variable
            name="context"
            type="com.qiangxi.functiontest.bean.StudentInfo"/>
    </data>

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

        <TextView
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_marginTop="3dp"
            android:gravity="center_vertical"
            android:text='@{String.valueOf(context.age)+@string/app_name}'
            android:visibility="@{context.age > 0 ? View.VISIBLE : View.GONE}"
            />
    </LinearLayout>
</layout>

虽然可以这么做,但是建议尽量不要定义和context名称相同的对象,以免混淆,不利于后期维护或别人阅读.

2.默认导入java.lang下的一些包

DataBinding已经默认帮我们导入了String类,Integer类等java.lang下的一些类,让我们可以更加便捷的使用相关方法,导入的方式为:

...

<import type = "java.lang.String"/>

...
评论