databinding学习笔记

本文是https://github.com/LyndonChin/MasteringAndroidDataBinding的学习笔记java

DataBinding简要

准备

保证Gradle插件版本不低于1.5.0-alpha1android

修改对应模块的build.gradle:git

dataBinding{
    enabled true
}

布局文件

最外层根节点变为layout,新增节点data用来存放页面可能用的数据以及方法。github

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
    </data>
    <!--原先的根节点(Root Element)-->
    <LinearLayout>
    ....
    </LinearLayout>
</layout>

数据对象

须要注意的是在数据对象中必须实现每一个属性的get和set方法。api

public class User {
    private final String firstName;
    private final String lastName;

    public User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }
}

若是须要双向绑定则须要继承BaseObservable类,该类实现了监听器的注册机制(未验证)。app

public class ObservableUser extends BaseObservable {
    private String firstName;
    private String lastName;

    @Bindable
    public String getFirstName() {
        return firstName;
    }

    @Bindable
    public String getLastName() {
        return lastName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
        notifyPropertyChanged(BR.firstName);
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
        notifyPropertyChanged(BR.lastName);
    }
}

BR 是编译阶段生成的一个类,功能与 R.java 相似,用 @Bindable 标记过 getter 方法会在 BR 中生成一个 entry框架

经过代码能够看出,当数据发生变化时仍是须要手动发出通知。 经过调用 notifyPropertyChanged(BR.firstName) 能够通知系统 BR.firstName 这个 entry 的数据已经发生变化,须要更新 UI。ide

Variable和import

这两个标签是在layout资源文件中data标签的下级标签,其中variable标签能够独自使用,其独自使用方法以下:布局

<data>
    <variable name="user" type="com.xxx.xxx.xxx.User" />
</data>

其中name对应的字段会在具体view控件赋值时用到,type字段对应值是具体引用的类的全路径。学习

variable和import方法联合使用方法以下:

<data>
    <import type="com.xxx.xxx.xxx.User" />
    <variable name="user" type="User" />
</data>

import使用方法与java相似,当使用了import后,variable的type标签就可使用类名而不是全路径了

多个路径类名相同的解决方法

<import type="com.example.home.data.User" />
<import type="com.examle.detail.data.User" alias="DetailUser" />
<variable name="user" type="DetailUser" />

如上面代码所示当引用了不一样路径的两个 User 类时,须要给其中一个设置别名alias,这样在给variable标签中的type字段赋值时就能够避免冲突。

绑定variable

当设置了variable标签后,框架会自动生成一个继承自ViewDataBinding的类,若是data中有class属性,好比

<data class="com.example.CustomBinding">
</data>

则生成的类名为CustomBinding,不然就根据layout的文件名来生成对应的Binding类,例如R.layout.activity_main对应生成的类名为ActivityMainBinding。自动生成的类在build目录下,as中不可见。

具体在Activity中的绑定方法以下

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityBasicBinding binding = DataBindingUtil.setContentView(
            this, R.layout.activity_basic);
    User user = new User("fei", "Liang");
    binding.setUser(user);
}

用DataBindingUtil.setContentView来获取一个ActivityBasicBinding的实例binding来实现绑定,binding经过set方法来设置variable中对应的属性。

除了setContentView方法外,DataBindingUtil还提供了一个静态方法bind(View v)来实现xml和对应的ViewDataBinding的绑定。该方法能够用于adper和fragment中的xml绑定。

使用variable

数据与 Variable 绑定以后,xml 的 UI 元素就能够直接使用了。使用方法为:属性="@{[variable.name].[property]}"例如:

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

java类静态方法的使用

首先定义一个静态方法

public class MyStringUtils {
    public static String capitalize(final String word) {
        if (word.length() > 1) {
            return String.valueOf(word.charAt(0)).toUpperCase() + word.substring(1);
        }
        return word;
    }
}

而后在 xml 的 data 节点中导入:

<import type="com.liangfeizc.databindingsamples.utils.MyStringUtils" />

使用方法与 Java 语法同样:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{MyStringUtils.capitalize(user.firstName)}" />

BindingAdapter

public class TestUtils{
    @BindingAdapter("bind:imageUrl")
    public static void imageLoader(ImageView view,String url){
        ImageLoader.getInstance().display(url,view)
    }
}
<?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 type="com.vip.vf.android.home.api.model.ActiveModel"></import>
        <import type="com.vip.vf.android.common.uitils.TestUtils"></import>
        <variable
            name="model"
            type="ActiveModel"/>
        <variable
            name="isBottom"
            type="boolean"/>
        <variable
            name="utils"
            type="TestUtils"/>
        <variable
            name="imageUrl"
            type="String"/>
    </data>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="@color/vfWhiteColor">
        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            app:imageUrl = "@{imageUrl}"
            />
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </RelativeLayout>
</layout>

以上代码实现的功能是经过设置xml中的imageUrl属性来调用java文件中TestUtils的方法imageLoader,具体须要加载图片的时候只要调用相应的binding class的setimageUrl方法便可完成,能够有效的避免在Activity代码中屡次引用ImageLoader这个方法。

自定义view的属性

自定义view能够直接经过set方法来连接xml的相应属性。

<com.xxx.xxx.xxx.UserView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="@dimen/largePadding"
    app:onClickListener="@{activity.clickListener}"
    app:firstName="@{@string/firstName}"
    app:lastName="@{@string/lastName}"
    app:age="27" />

在如上xml布局文件中,有两个属性firstName和lastName,只要在Java文件UserView中实现两个set方法,不须要专门写style属性。

public void setFirstName(@NonNull final String firstName){
    mFirstName.setText(firstName);
}
public void setLastName(@NonNull final String lastName) {
    mLastName.setText(lastName);
}

带 ID 的 View

Data Binding 有效下降了代码的冗余性,甚至彻底没有必要再去获取一个 View 实例,可是状况不是绝对的,万一咱们真的就须要了呢?不用担忧,只要给 View 定义一个 ID,Data Binding 就会为咱们生成一个对应的 final 变量。

<TextView
    android:id="@+id/firstName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

上面代码中定义了一个 ID 为 *firstName** 的 TextView,那么它对应的变量就是

public final TextView firstName;

使用时咱们直接调用相应的binding.firstName就能够对应到相应的TextView

Null Coalescing 运算符

android:text="@{user.displayName ?? user.lastName}"

就等价于

android:text="@{user.displayName != null ? user.displayName : user.lastName}"

属性值

经过 @{} 能够直接把 Java 中定义的属性值赋值给 xml 属性。

<TextView
   android:text="@{user.lastName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>

使用资源数据

<TextView
    android:padding="@{large? (int)@dimen/largePadding : (int)@dimen/smallPadding}"
    android:background="@android:color/black"
    android:textColor="@android:color/white"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world" />
相关文章
相关标签/搜索